mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:39:49 +00:00
[dartdevc] Adding nnbd semantics for static and late fields.
Fixes #40375 Change-Id: I53863291a8c6a3cc694d088311a9e09b9b00a790 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138723 Commit-Queue: Mark Zhou <markzipan@google.com> Reviewed-by: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
parent
fa2df01895
commit
8fb4645cae
|
@ -348,7 +348,7 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
// emitted before dart.defineLazy.
|
||||
if (_constLazyAccessors.isNotEmpty) {
|
||||
var constTableBody = runtimeStatement(
|
||||
'defineLazy(#, { # })', [_constTable, _constLazyAccessors]);
|
||||
'defineLazy(#, { # }, false)', [_constTable, _constLazyAccessors]);
|
||||
moduleItems.insert(_constTableInsertionIndex, constTableBody);
|
||||
_constLazyAccessors.clear();
|
||||
}
|
||||
|
@ -2106,10 +2106,13 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
|
|||
}
|
||||
_staticTypeContext.leaveMember(field);
|
||||
}
|
||||
_currentUri = _currentLibrary.fileUri;
|
||||
|
||||
_currentUri = savedUri;
|
||||
return runtimeStatement('defineLazy(#, { # })', [objExpr, accessors]);
|
||||
|
||||
return runtimeStatement('defineLazy(#, { # }, #)', [
|
||||
objExpr,
|
||||
accessors,
|
||||
js.boolean(!_currentLibrary.isNonNullableByDefault)
|
||||
]);
|
||||
}
|
||||
|
||||
js_ast.Fun _emitStaticFieldInitializer(Field field) {
|
||||
|
|
|
@ -697,7 +697,7 @@ _canonicalMember(obj, name) {
|
|||
Future loadLibrary() => Future.value();
|
||||
|
||||
/// Defines lazy statics.
|
||||
void defineLazy(to, from) {
|
||||
void defineLazy(to, from, bool checkCycles) {
|
||||
for (var name in getOwnNamesAndSymbols(from)) {
|
||||
defineLazyField(to, name, getOwnPropertyDescriptor(from, name));
|
||||
}
|
||||
|
|
|
@ -741,8 +741,89 @@ _canonicalMember(obj, name) {
|
|||
Future loadLibrary() => Future.value();
|
||||
|
||||
/// Defines lazy statics.
|
||||
void defineLazy(to, from) {
|
||||
///
|
||||
/// TODO: Remove useOldSemantics when non-null-safe late static field behavior is
|
||||
/// deprecated.
|
||||
void defineLazy(to, from, bool useOldSemantics) {
|
||||
for (var name in getOwnNamesAndSymbols(from)) {
|
||||
defineLazyField(to, name, getOwnPropertyDescriptor(from, name));
|
||||
if (useOldSemantics) {
|
||||
defineLazyFieldOld(to, name, getOwnPropertyDescriptor(from, name));
|
||||
} else {
|
||||
defineLazyField(to, name, getOwnPropertyDescriptor(from, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a lazy static field.
|
||||
/// After initial get or set, it will replace itself with a value property.
|
||||
// TODO(jmesserly): reusing descriptor objects has been shown to improve
|
||||
// performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
|
||||
defineLazyField(to, name, desc) => JS('', '''(() => {
|
||||
const initializer = $desc.get;
|
||||
let init = initializer;
|
||||
let value = null;
|
||||
let executed = false;
|
||||
$desc.get = function() {
|
||||
if (init == null) return value;
|
||||
if (!executed) {
|
||||
// Record the field on first execution so we can reset it later if
|
||||
// needed (hot restart).
|
||||
$_resetFields.push(() => {
|
||||
init = initializer;
|
||||
value = null;
|
||||
});
|
||||
executed = true;
|
||||
}
|
||||
value = init();
|
||||
init = null;
|
||||
return value;
|
||||
};
|
||||
$desc.configurable = true;
|
||||
if ($desc.set != null) {
|
||||
$desc.set = function(x) {
|
||||
init = null;
|
||||
value = x;
|
||||
};
|
||||
}
|
||||
return ${defineProperty(to, name, desc)};
|
||||
})()''');
|
||||
|
||||
/// Defines a lazy static field with pre-null-safety semantics.
|
||||
defineLazyFieldOld(to, name, desc) => JS('', '''(() => {
|
||||
const initializer = $desc.get;
|
||||
let init = initializer;
|
||||
let value = null;
|
||||
$desc.get = function() {
|
||||
if (init == null) return value;
|
||||
let f = init;
|
||||
init = $throwCyclicInitializationError;
|
||||
if (f === init) f($name); // throw cycle error
|
||||
|
||||
// On the first (non-cyclic) execution, record the field so we can reset it
|
||||
// later if needed (hot restart).
|
||||
$_resetFields.push(() => {
|
||||
init = initializer;
|
||||
value = null;
|
||||
});
|
||||
|
||||
// Try to evaluate the field, using try+catch to ensure we implement the
|
||||
// correct Dart error semantics.
|
||||
try {
|
||||
value = f();
|
||||
init = null;
|
||||
return value;
|
||||
} catch (e) {
|
||||
init = null;
|
||||
value = null;
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
$desc.configurable = true;
|
||||
if ($desc.set != null) {
|
||||
$desc.set = function(x) {
|
||||
init = null;
|
||||
value = x;
|
||||
};
|
||||
}
|
||||
return ${defineProperty(to, name, desc)};
|
||||
})()''');
|
||||
|
|
|
@ -60,49 +60,6 @@ safeGetOwnProperty(obj, name) {
|
|||
return JS<Object>('', '#[#]', obj, name);
|
||||
}
|
||||
|
||||
/// Defines a lazy static field.
|
||||
/// After initial get or set, it will replace itself with a value property.
|
||||
// TODO(jmesserly): reusing descriptor objects has been shown to improve
|
||||
// performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
|
||||
defineLazyField(to, name, desc) => JS('', '''(() => {
|
||||
const initializer = $desc.get;
|
||||
let init = initializer;
|
||||
let value = null;
|
||||
$desc.get = function() {
|
||||
if (init == null) return value;
|
||||
let f = init;
|
||||
init = $throwCyclicInitializationError;
|
||||
if (f === init) f($name); // throw cycle error
|
||||
|
||||
// On the first (non-cyclic) execution, record the field so we can reset it
|
||||
// later if needed (hot restart).
|
||||
$_resetFields.push(() => {
|
||||
init = initializer;
|
||||
value = null;
|
||||
});
|
||||
|
||||
// Try to evaluate the field, using try+catch to ensure we implement the
|
||||
// correct Dart error semantics.
|
||||
try {
|
||||
value = f();
|
||||
init = null;
|
||||
return value;
|
||||
} catch (e) {
|
||||
init = null;
|
||||
value = null;
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
$desc.configurable = true;
|
||||
if ($desc.set != null) {
|
||||
$desc.set = function(x) {
|
||||
init = null;
|
||||
value = x;
|
||||
};
|
||||
}
|
||||
return ${defineProperty(to, name, desc)};
|
||||
})()''');
|
||||
|
||||
copyTheseProperties(to, from, names) {
|
||||
for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
|
||||
var name = JS('', '#[#]', names, i);
|
||||
|
|
Loading…
Reference in a new issue