[dart2js] Implement Cell lowering for uninitialized locals.

Change-Id: I7233e1484cc19e5f24d215bfd2c1e34c8f12961b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193588
Commit-Queue: Mayank Patke <fishythefish@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Mayank Patke 2021-04-07 19:43:07 +00:00 committed by commit-bot@chromium.org
parent c089922d2a
commit 8f832e2c6b
8 changed files with 346 additions and 216 deletions

View file

@ -62,10 +62,6 @@ int _foldLateLowerings(List<int> lowerings) =>
/// Late lowerings which the frontend performs for dart2js.
const List<int> _allEnabledLateLowerings = [
LateLowering.nullableUninitializedNonFinalLocal,
LateLowering.nonNullableUninitializedNonFinalLocal,
LateLowering.nullableUninitializedFinalLocal,
LateLowering.nonNullableUninitializedFinalLocal,
LateLowering.nullableInitializedNonFinalLocal,
LateLowering.nonNullableInitializedNonFinalLocal,
LateLowering.nullableInitializedFinalLocal,
@ -167,8 +163,7 @@ class Dart2jsTarget extends Target {
_nativeClasses)
.visitLibrary(library);
}
lowering.transformLibraries(
libraries, coreTypes, hierarchy, flags.enableNullSafety);
lowering.transformLibraries(libraries, coreTypes, hierarchy);
logger?.call("Lowering transformations performed");
}

View file

@ -0,0 +1,112 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart';
import 'package:kernel/library_index.dart';
import 'package:kernel/type_algebra.dart';
bool _shouldLowerVariable(VariableDeclaration node) =>
node.initializer == null && node.isLate;
class LateLowering {
final Class _cellClass;
final Constructor _cellConstructor;
final Procedure _readLocal;
List<TypeParameter> _readLocalTypeParameters;
FunctionType _readLocalTypeWithoutTypeParameters;
final Procedure _setValue;
final Procedure _setFinalLocalValue;
final Map<VariableDeclaration, VariableDeclaration> _cells = {};
Member _contextMember;
LateLowering(LibraryIndex index)
: _cellClass = index.getClass('dart:_late_helper', '_Cell'),
_cellConstructor = index.getMember('dart:_late_helper', '_Cell', ''),
_readLocal = index.getMember('dart:_late_helper', '_Cell', 'readLocal'),
_setValue = index.getMember('dart:_late_helper', '_Cell', 'set:value'),
_setFinalLocalValue = index.getMember(
'dart:_late_helper', '_Cell', 'set:finalLocalValue') {
FunctionType _readLocalType = _readLocal.getterType;
_readLocalTypeParameters = _readLocalType.typeParameters;
_readLocalTypeWithoutTypeParameters = _readLocalType.withoutTypeParameters;
}
VariableDeclaration _variableCell(VariableDeclaration variable) {
assert(_shouldLowerVariable(variable));
return _cells.putIfAbsent(variable, () {
int fileOffset = variable.fileOffset;
return VariableDeclaration(variable.name,
initializer:
ConstructorInvocation(_cellConstructor, Arguments.empty())
..fileOffset = fileOffset,
type: InterfaceType(
_cellClass, _contextMember.enclosingLibrary.nonNullable),
isFinal: true)
..fileOffset = fileOffset;
});
}
VariableGet _variableCellAccess(
VariableDeclaration variable, int fileOffset) =>
VariableGet(_variableCell(variable))..fileOffset = fileOffset;
TreeNode transformVariableDeclaration(
VariableDeclaration node, Member contextMember) {
_contextMember = contextMember;
if (!_shouldLowerVariable(node)) return node;
// A [VariableDeclaration] being used as a statement must be a direct child
// of a [Block].
if (node.parent is! Block) return node;
return _variableCell(node);
}
TreeNode transformVariableGet(VariableGet node, Member contextMember) {
_contextMember = contextMember;
VariableDeclaration variable = node.variable;
if (!_shouldLowerVariable(variable)) return node;
int fileOffset = node.fileOffset;
VariableGet cell = _variableCellAccess(variable, fileOffset);
List<DartType> typeArguments = [node.promotedType ?? variable.type];
return InstanceInvocation(
InstanceAccessKind.Instance,
cell,
_readLocal.name,
Arguments(const [], types: typeArguments)..fileOffset = fileOffset,
interfaceTarget: _readLocal,
functionType:
Substitution.fromPairs(_readLocalTypeParameters, typeArguments)
.substituteType(_readLocalTypeWithoutTypeParameters))
..fileOffset = fileOffset;
}
TreeNode transformVariableSet(VariableSet node, Member contextMember) {
_contextMember = contextMember;
VariableDeclaration variable = node.variable;
if (!_shouldLowerVariable(variable)) return node;
int fileOffset = node.fileOffset;
VariableGet cell = _variableCellAccess(variable, fileOffset);
if (variable.isFinal) {
return InstanceSet(InstanceAccessKind.Instance, cell,
_setFinalLocalValue.name, node.value,
interfaceTarget: _setFinalLocalValue)
..fileOffset = fileOffset;
} else {
return InstanceSet(
InstanceAccessKind.Instance, cell, _setValue.name, node.value,
interfaceTarget: _setValue)
..fileOffset = fileOffset;
}
}
}

View file

@ -5,52 +5,57 @@
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/type_environment.dart'
show StaticTypeContext, TypeEnvironment;
import 'factory_specializer.dart';
import 'late_lowering.dart';
/// dart2js-specific lowering transformations and optimizations combined into a
/// single transformation pass.
///
/// Each transformation is applied locally to AST nodes of certain types after
/// transforming children nodes.
void transformLibraries(List<Library> libraries, CoreTypes coreTypes,
ClassHierarchy hierarchy, bool nullSafety) {
final transformer = _Lowering(coreTypes, hierarchy, nullSafety);
void transformLibraries(
List<Library> libraries, CoreTypes coreTypes, ClassHierarchy hierarchy) {
final transformer = _Lowering(coreTypes, hierarchy);
libraries.forEach(transformer.visitLibrary);
}
class _Lowering extends Transformer {
final TypeEnvironment env;
final bool nullSafety;
final FactorySpecializer factorySpecializer;
final LateLowering _lateLowering;
Member _currentMember;
StaticTypeContext _cachedStaticTypeContext;
_Lowering(CoreTypes coreTypes, ClassHierarchy hierarchy, this.nullSafety)
: env = TypeEnvironment(coreTypes, hierarchy),
factorySpecializer = FactorySpecializer(coreTypes, hierarchy);
// ignore: unused_element
StaticTypeContext get _staticTypeContext =>
_cachedStaticTypeContext ??= StaticTypeContext(_currentMember, env);
_Lowering(CoreTypes coreTypes, ClassHierarchy hierarchy)
: factorySpecializer = FactorySpecializer(coreTypes, hierarchy),
_lateLowering = LateLowering(coreTypes.index);
@override
defaultMember(Member node) {
TreeNode defaultMember(Member node) {
_currentMember = node;
_cachedStaticTypeContext = null;
final result = super.defaultMember(node);
_currentMember = null;
_cachedStaticTypeContext = null;
return result;
return super.defaultMember(node);
}
@override
visitStaticInvocation(StaticInvocation node) {
TreeNode visitStaticInvocation(StaticInvocation node) {
node.transformChildren(this);
return factorySpecializer.transformStaticInvocation(node, _currentMember);
}
@override
TreeNode visitVariableDeclaration(VariableDeclaration node) {
node.transformChildren(this);
return _lateLowering.transformVariableDeclaration(node, _currentMember);
}
@override
TreeNode visitVariableGet(VariableGet node) {
node.transformChildren(this);
return _lateLowering.transformVariableGet(node, _currentMember);
}
@override
TreeNode visitVariableSet(VariableSet node) {
node.transformChildren(this);
return _lateLowering.transformVariableSet(node, _currentMember);
}
}

View file

@ -14,61 +14,39 @@ static method main() → void {
self::testNonNullableInitializedFinalLocal();
}
static method testNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateError::localNI("x") : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
late core::int? x;
x = 42;
core::print(x{core::int});
}
static method testNonNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x;
function #x#get() → core::int
return let final core::int? #t3 = #x in #t3 == null ?{core::int} throw new _in::LateError::localNI("x") : #t3{core::int};
function #x#set(core::int #t4) → dynamic
return #x = #t4;
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
late core::int x;
x = 42;
core::print(x);
}
static method testNullableUninitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t5 = #x in _in::isSentinel(#t5) ?{core::int?} throw new _in::LateError::localNI("x") : #t5{core::int?};
function #x#set(core::int? #t6) → dynamic
if(_in::isSentinel(#x))
return #x = #t6;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
late final core::int? x;
x = 42;
core::print(x{core::int});
}
static method testNonNullableUninitializedFinalLocal() → void {
lowered final core::int? #x;
function #x#get() → core::int
return let final core::int? #t7 = #x in #t7 == null ?{core::int} throw new _in::LateError::localNI("x") : #t7{core::int};
function #x#set(core::int #t8) → dynamic
if(#x == null)
return #x = #t8;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
late final core::int x;
x = 42;
core::print(x);
}
static method testNullableInitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t9 = #x in _in::isSentinel(#t9) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t9{core::int?};
function #x#set(core::int? #t10) → dynamic
return #x = #t10;
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
core::print(#x#get(){() → core::int?});
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
lowered core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t11 = #y in _in::isSentinel(#t11) ?{core::int?} #y = null : #t11{core::int?};
function #y#set(core::int? #t12) → dynamic
return #y = #t12;
return let final core::int? #t3 = #y in _in::isSentinel(#t3) ?{core::int?} #y = null : #t3{core::int?};
function #y#set(core::int? #t4) → dynamic
return #y = #t4;
core::print(#y#get(){() → core::int?});
#y#set(42){(core::int?) → dynamic};
core::print(#y#get(){() → core::int?});
@ -76,9 +54,9 @@ static method testNullableInitializedNonFinalLocal() → void {
static method testNonNullableInitializedNonFinalLocal() → void {
lowered core::int? #x;
function #x#get() → core::int
return let final core::int? #t13 = #x in #t13 == null ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t13{core::int};
function #x#set(core::int #t14) → dynamic
return #x = #t14;
return let final core::int? #t5 = #x in #t5 == null ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
function #x#set(core::int #t6) → dynamic
return #x = #t6;
core::print(#x#get(){() → core::int});
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
@ -86,16 +64,16 @@ static method testNonNullableInitializedNonFinalLocal() → void {
static method testNullableInitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t15 = #x in _in::isSentinel(#t15) ?{core::int?} let final core::int? #t16 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t16 : throw new _in::LateError::localADI("x") : #t15;
return let final core::int? #t7 = #x in _in::isSentinel(#t7) ?{core::int?} let final core::int? #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t8 : throw new _in::LateError::localADI("x") : #t7;
core::print(#x#get(){() → core::int?});
lowered final core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t17 = #y in _in::isSentinel(#t17) ?{core::int?} let final core::int? #t18 = null in _in::isSentinel(#y) ?{core::int?} #y = #t18 : throw new _in::LateError::localADI("y") : #t17;
return let final core::int? #t9 = #y in _in::isSentinel(#t9) ?{core::int?} let final core::int? #t10 = null in _in::isSentinel(#y) ?{core::int?} #y = #t10 : throw new _in::LateError::localADI("y") : #t9;
core::print(#y#get(){() → core::int?});
}
static method testNonNullableInitializedFinalLocal() → void {
lowered final core::int? #x;
function #x#get() → core::int
return let final core::int? #t19 = #x in #t19 == null ?{core::int} let final core::int #t20 = 1.{core::int::unary-}(){() → core::int} in #x == null ?{core::int} #x = #t20 : throw new _in::LateError::localADI("x") : #t19{core::int};
return let final core::int? #t11 = #x in #t11 == null ?{core::int} let final core::int #t12 = 1.{core::int::unary-}(){() → core::int} in #x == null ?{core::int} #x = #t12 : throw new _in::LateError::localADI("x") : #t11{core::int};
core::print(#x#get(){() → core::int});
}

View file

@ -1,5 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:_late_helper" as _la;
import "dart:core" as core;
import "dart:_internal" as _in;
@ -14,61 +15,39 @@ static method main() → void {
self::testNonNullableInitializedFinalLocal();
}
static method testNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateError::localNI("x") : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::value} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNonNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x;
function #x#get() → core::int
return let final core::int? #t3 = #x in #t3 == null ?{core::int} throw new _in::LateError::localNI("x") : #t3{core::int};
function #x#set(core::int #t4) → dynamic
return #x = #t4;
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::value} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNullableUninitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t5 = #x in _in::isSentinel(#t5) ?{core::int?} throw new _in::LateError::localNI("x") : #t5{core::int?};
function #x#set(core::int? #t6) → dynamic
if(_in::isSentinel(#x))
return #x = #t6;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::finalLocalValue} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNonNullableUninitializedFinalLocal() → void {
lowered final core::int? #x;
function #x#get() → core::int
return let final core::int? #t7 = #x in #t7 == null ?{core::int} throw new _in::LateError::localNI("x") : #t7{core::int};
function #x#set(core::int #t8) → dynamic
if(#x == null)
return #x = #t8;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::finalLocalValue} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNullableInitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t9 = #x in _in::isSentinel(#t9) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t9{core::int?};
function #x#set(core::int? #t10) → dynamic
return #x = #t10;
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
core::print(#x#get(){() → core::int?});
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
lowered core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t11 = #y in _in::isSentinel(#t11) ?{core::int?} #y = null : #t11{core::int?};
function #y#set(core::int? #t12) → dynamic
return #y = #t12;
return let final core::int? #t3 = #y in _in::isSentinel(#t3) ?{core::int?} #y = null : #t3{core::int?};
function #y#set(core::int? #t4) → dynamic
return #y = #t4;
core::print(#y#get(){() → core::int?});
#y#set(42){(core::int?) → dynamic};
core::print(#y#get(){() → core::int?});
@ -76,9 +55,9 @@ static method testNullableInitializedNonFinalLocal() → void {
static method testNonNullableInitializedNonFinalLocal() → void {
lowered core::int? #x;
function #x#get() → core::int
return let final core::int? #t13 = #x in #t13 == null ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t13{core::int};
function #x#set(core::int #t14) → dynamic
return #x = #t14;
return let final core::int? #t5 = #x in #t5 == null ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
function #x#set(core::int #t6) → dynamic
return #x = #t6;
core::print(#x#get(){() → core::int});
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
@ -86,17 +65,17 @@ static method testNonNullableInitializedNonFinalLocal() → void {
static method testNullableInitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t15 = #x in _in::isSentinel(#t15) ?{core::int?} let final core::int? #t16 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t16 : throw new _in::LateError::localADI("x") : #t15;
return let final core::int? #t7 = #x in _in::isSentinel(#t7) ?{core::int?} let final core::int? #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t8 : throw new _in::LateError::localADI("x") : #t7;
core::print(#x#get(){() → core::int?});
lowered final core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t17 = #y in _in::isSentinel(#t17) ?{core::int?} let final core::int? #t18 = null in _in::isSentinel(#y) ?{core::int?} #y = #t18 : throw new _in::LateError::localADI("y") : #t17;
return let final core::int? #t9 = #y in _in::isSentinel(#t9) ?{core::int?} let final core::int? #t10 = null in _in::isSentinel(#y) ?{core::int?} #y = #t10 : throw new _in::LateError::localADI("y") : #t9;
core::print(#y#get(){() → core::int?});
}
static method testNonNullableInitializedFinalLocal() → void {
lowered final core::int? #x;
function #x#get() → core::int
return let final core::int? #t19 = #x in #t19 == null ?{core::int} let final core::int #t20 = 1.{core::int::unary-}(){() → core::int} in #x == null ?{core::int} #x = #t20 : throw new _in::LateError::localADI("x") : #t19{core::int};
return let final core::int? #t11 = #x in #t11 == null ?{core::int} let final core::int #t12 = 1.{core::int::unary-}(){() → core::int} in #x == null ?{core::int} #x = #t12 : throw new _in::LateError::localADI("x") : #t11{core::int};
core::print(#x#get(){() → core::int});
}
@ -109,4 +88,4 @@ Evaluated: VariableGet @ org-dartlang-testcase:///late_locals.dart:60:19 -> Doub
Evaluated: VariableGet @ org-dartlang-testcase:///late_locals.dart:63:19 -> NullConstant(null)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_locals.dart:68:22 -> DoubleConstant(-1.0)
Evaluated: VariableGet @ org-dartlang-testcase:///late_locals.dart:68:18 -> DoubleConstant(-1.0)
Extra constant evaluation: evaluated: 168, effectively constant: 7
Extra constant evaluation: evaluated: 130, effectively constant: 7

View file

@ -14,61 +14,39 @@ static method main() → void {
self::testNonNullableInitializedFinalLocal();
}
static method testNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateError::localNI("x") : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
late core::int? x;
x = 42;
core::print(x{core::int});
}
static method testNonNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int? #t3 = #x in _in::isSentinel(#t3) ?{core::int} throw new _in::LateError::localNI("x") : #t3{core::int};
function #x#set(core::int #t4) → dynamic
return #x = #t4;
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
late core::int x;
x = 42;
core::print(x);
}
static method testNullableUninitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t5 = #x in _in::isSentinel(#t5) ?{core::int?} throw new _in::LateError::localNI("x") : #t5{core::int?};
function #x#set(core::int? #t6) → dynamic
if(_in::isSentinel(#x))
return #x = #t6;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
late final core::int? x;
x = 42;
core::print(x{core::int});
}
static method testNonNullableUninitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int? #t7 = #x in _in::isSentinel(#t7) ?{core::int} throw new _in::LateError::localNI("x") : #t7{core::int};
function #x#set(core::int #t8) → dynamic
if(_in::isSentinel(#x))
return #x = #t8;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
late final core::int x;
x = 42;
core::print(x);
}
static method testNullableInitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t9 = #x in _in::isSentinel(#t9) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t9{core::int?};
function #x#set(core::int? #t10) → dynamic
return #x = #t10;
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
core::print(#x#get(){() → core::int?});
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
lowered core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t11 = #y in _in::isSentinel(#t11) ?{core::int?} #y = null : #t11{core::int?};
function #y#set(core::int? #t12) → dynamic
return #y = #t12;
return let final core::int? #t3 = #y in _in::isSentinel(#t3) ?{core::int?} #y = null : #t3{core::int?};
function #y#set(core::int? #t4) → dynamic
return #y = #t4;
core::print(#y#get(){() → core::int?});
#y#set(42){(core::int?) → dynamic};
core::print(#y#get(){() → core::int?});
@ -76,9 +54,9 @@ static method testNullableInitializedNonFinalLocal() → void {
static method testNonNullableInitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int? #t13 = #x in _in::isSentinel(#t13) ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t13{core::int};
function #x#set(core::int #t14) → dynamic
return #x = #t14;
return let final core::int? #t5 = #x in _in::isSentinel(#t5) ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
function #x#set(core::int #t6) → dynamic
return #x = #t6;
core::print(#x#get(){() → core::int});
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
@ -86,16 +64,16 @@ static method testNonNullableInitializedNonFinalLocal() → void {
static method testNullableInitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t15 = #x in _in::isSentinel(#t15) ?{core::int?} let final core::int? #t16 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t16 : throw new _in::LateError::localADI("x") : #t15;
return let final core::int? #t7 = #x in _in::isSentinel(#t7) ?{core::int?} let final core::int? #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t8 : throw new _in::LateError::localADI("x") : #t7;
core::print(#x#get(){() → core::int?});
lowered final core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t17 = #y in _in::isSentinel(#t17) ?{core::int?} let final core::int? #t18 = null in _in::isSentinel(#y) ?{core::int?} #y = #t18 : throw new _in::LateError::localADI("y") : #t17;
return let final core::int? #t9 = #y in _in::isSentinel(#t9) ?{core::int?} let final core::int? #t10 = null in _in::isSentinel(#y) ?{core::int?} #y = #t10 : throw new _in::LateError::localADI("y") : #t9;
core::print(#y#get(){() → core::int?});
}
static method testNonNullableInitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int #t19 = #x in _in::isSentinel(#t19) ?{core::int} let final core::int #t20 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int} #x = #t20 : throw new _in::LateError::localADI("x") : #t19;
return let final core::int #t11 = #x in _in::isSentinel(#t11) ?{core::int} let final core::int #t12 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int} #x = #t12 : throw new _in::LateError::localADI("x") : #t11;
core::print(#x#get(){() → core::int});
}

View file

@ -1,5 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:_late_helper" as _la;
import "dart:core" as core;
import "dart:_internal" as _in;
@ -14,61 +15,39 @@ static method main() → void {
self::testNonNullableInitializedFinalLocal();
}
static method testNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateError::localNI("x") : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::value} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNonNullableUninitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int? #t3 = #x in _in::isSentinel(#t3) ?{core::int} throw new _in::LateError::localNI("x") : #t3{core::int};
function #x#set(core::int #t4) → dynamic
return #x = #t4;
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::value} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNullableUninitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t5 = #x in _in::isSentinel(#t5) ?{core::int?} throw new _in::LateError::localNI("x") : #t5{core::int?};
function #x#set(core::int? #t6) → dynamic
if(_in::isSentinel(#x))
return #x = #t6;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::finalLocalValue} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNonNullableUninitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int? #t7 = #x in _in::isSentinel(#t7) ?{core::int} throw new _in::LateError::localNI("x") : #t7{core::int};
function #x#set(core::int #t8) → dynamic
if(_in::isSentinel(#x))
return #x = #t8;
else
throw new _in::LateError::localAI("x");
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
final _la::_Cell x = new _la::_Cell::•();
x.{_la::_Cell::finalLocalValue} = 42;
core::print(x.{_la::_Cell::readLocal}<core::int>(){() → core::int});
}
static method testNullableInitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t9 = #x in _in::isSentinel(#t9) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t9{core::int?};
function #x#set(core::int? #t10) → dynamic
return #x = #t10;
return let final core::int? #t1 = #x in _in::isSentinel(#t1) ?{core::int?} #x = 1.{core::int::unary-}(){() → core::int} : #t1{core::int?};
function #x#set(core::int? #t2) → dynamic
return #x = #t2;
core::print(#x#get(){() → core::int?});
#x#set(42){(core::int?) → dynamic};
core::print(#x#get(){() → core::int?});
lowered core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t11 = #y in _in::isSentinel(#t11) ?{core::int?} #y = null : #t11{core::int?};
function #y#set(core::int? #t12) → dynamic
return #y = #t12;
return let final core::int? #t3 = #y in _in::isSentinel(#t3) ?{core::int?} #y = null : #t3{core::int?};
function #y#set(core::int? #t4) → dynamic
return #y = #t4;
core::print(#y#get(){() → core::int?});
#y#set(42){(core::int?) → dynamic};
core::print(#y#get(){() → core::int?});
@ -76,9 +55,9 @@ static method testNullableInitializedNonFinalLocal() → void {
static method testNonNullableInitializedNonFinalLocal() → void {
lowered core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int? #t13 = #x in _in::isSentinel(#t13) ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t13{core::int};
function #x#set(core::int #t14) → dynamic
return #x = #t14;
return let final core::int? #t5 = #x in _in::isSentinel(#t5) ?{core::int} #x = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
function #x#set(core::int #t6) → dynamic
return #x = #t6;
core::print(#x#get(){() → core::int});
#x#set(42){(core::int) → dynamic};
core::print(#x#get(){() → core::int});
@ -86,17 +65,17 @@ static method testNonNullableInitializedNonFinalLocal() → void {
static method testNullableInitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int?>();
function #x#get() → core::int?
return let final core::int? #t15 = #x in _in::isSentinel(#t15) ?{core::int?} let final core::int? #t16 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t16 : throw new _in::LateError::localADI("x") : #t15;
return let final core::int? #t7 = #x in _in::isSentinel(#t7) ?{core::int?} let final core::int? #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int?} #x = #t8 : throw new _in::LateError::localADI("x") : #t7;
core::print(#x#get(){() → core::int?});
lowered final core::int? #y = _in::createSentinel<core::int?>();
function #y#get() → core::int?
return let final core::int? #t17 = #y in _in::isSentinel(#t17) ?{core::int?} let final core::int? #t18 = null in _in::isSentinel(#y) ?{core::int?} #y = #t18 : throw new _in::LateError::localADI("y") : #t17;
return let final core::int? #t9 = #y in _in::isSentinel(#t9) ?{core::int?} let final core::int? #t10 = null in _in::isSentinel(#y) ?{core::int?} #y = #t10 : throw new _in::LateError::localADI("y") : #t9;
core::print(#y#get(){() → core::int?});
}
static method testNonNullableInitializedFinalLocal() → void {
lowered final core::int? #x = _in::createSentinel<core::int>();
function #x#get() → core::int
return let final core::int #t19 = #x in _in::isSentinel(#t19) ?{core::int} let final core::int #t20 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int} #x = #t20 : throw new _in::LateError::localADI("x") : #t19;
return let final core::int #t11 = #x in _in::isSentinel(#t11) ?{core::int} let final core::int #t12 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(#x) ?{core::int} #x = #t12 : throw new _in::LateError::localADI("x") : #t11;
core::print(#x#get(){() → core::int});
}
@ -109,4 +88,4 @@ Evaluated: VariableGet @ org-dartlang-testcase:///late_locals.dart:60:19 -> Doub
Evaluated: VariableGet @ org-dartlang-testcase:///late_locals.dart:63:19 -> NullConstant(null)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_locals.dart:68:22 -> DoubleConstant(-1.0)
Evaluated: VariableGet @ org-dartlang-testcase:///late_locals.dart:68:18 -> DoubleConstant(-1.0)
Extra constant evaluation: evaluated: 172, effectively constant: 7
Extra constant evaluation: evaluated: 132, effectively constant: 7

View file

@ -0,0 +1,104 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
class Foo {
int x = 0;
int _y = 0;
int get y => _y;
void set y(int y) => _y = y;
static late int z;
late int w;
}
void main() {
final foo = Foo();
int a = 0;
late int b;
late int c;
late int d;
b = a = 1;
Expect.equals(a, 1);
Expect.equals(b, 1);
a = b = 2;
Expect.equals(a, 2);
Expect.equals(b, 2);
b = foo.x = 3;
Expect.equals(foo.x, 3);
Expect.equals(b, 3);
foo.x = b = 4;
Expect.equals(foo.x, 4);
Expect.equals(b, 4);
b = foo.y = 5;
Expect.equals(foo.y, 5);
Expect.equals(b, 5);
foo.y = b = 6;
Expect.equals(foo.y, 6);
Expect.equals(b, 6);
b = c = 7;
Expect.equals(b, 7);
Expect.equals(c, 7);
d = b = 8;
Expect.equals(b, 8);
Expect.equals(d, 8);
Foo.z = a = 9;
Expect.equals(a, 9);
Expect.equals(Foo.z, 9);
a = Foo.z = 10;
Expect.equals(a, 10);
Expect.equals(Foo.z, 10);
Foo.z = foo.x = 11;
Expect.equals(foo.x, 11);
Expect.equals(Foo.z, 11);
foo.x = Foo.z = 12;
Expect.equals(foo.x, 12);
Expect.equals(Foo.z, 12);
Foo.z = foo.y = 13;
Expect.equals(foo.y, 13);
Expect.equals(Foo.z, 13);
foo.y = Foo.z = 14;
Expect.equals(foo.y, 14);
Expect.equals(Foo.z, 14);
foo.w = a = 15;
Expect.equals(a, 15);
Expect.equals(foo.w, 15);
a = foo.w = 16;
Expect.equals(a, 16);
Expect.equals(foo.w, 16);
foo.w = foo.x = 17;
Expect.equals(foo.x, 17);
Expect.equals(foo.w, 17);
foo.x = foo.w = 18;
Expect.equals(foo.x, 18);
Expect.equals(foo.w, 18);
foo.w = foo.y = 19;
Expect.equals(foo.y, 19);
Expect.equals(foo.w, 19);
foo.y = foo.w = 20;
Expect.equals(foo.y, 20);
Expect.equals(foo.w, 20);
}