Add summary support for isLate
Change-Id: I21fe14778e24477f234e2a1a1fe65a23ebd05e7f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100274
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index f125cda..58b9e00 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1054,13 +1054,6 @@
/// Return `true` if this element is an enum constant.
bool get isEnumConstant;
- /// Return `true` if this field uses late evaluation semantics.
- ///
- /// This will always return `false` unless the experiment 'non-nullable' is
- /// enabled.
- @experimental
- bool get isLate;
-
/// Returns `true` if this field can be overridden in strong mode.
@deprecated
bool get isVirtual;
@@ -1542,6 +1535,13 @@
/// will be synthetic.
PropertyAccessorElement get getter;
+ /// Return `true` if this variable uses late evaluation semantics.
+ ///
+ /// This will always return `false` unless the experiment 'non-nullable' is
+ /// enabled.
+ @experimental
+ bool get isLate;
+
/// Return the propagated type of this variable, or `null` if type propagation
/// has not been performed, for example because the variable is not final.
@deprecated
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index f00dc09..f5d309f 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -7785,6 +7785,7 @@
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
_visitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
+ _visitTokenWithSuffix(node.lateKeyword, " ");
_visitTokenWithSuffix(node.keyword, " ");
_visitNodeWithSuffix(node.type, " ");
_visitNodeListWithSeparator(node.variables, ", ");
@@ -9046,6 +9047,7 @@
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
+ safelyVisitTokenWithSuffix(node.lateKeyword, " ");
safelyVisitTokenWithSuffix(node.keyword, " ");
safelyVisitNodeWithSuffix(node.type, " ");
safelyVisitNodeListWithSeparator(node.variables, ", ");
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 69973f8..6ae5195 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4946,17 +4946,6 @@
enclosingElement != null && enclosingElement.isEnum && !isSynthetic;
@override
- bool get isLate {
-// if (linkedNode != null) {
-// return enclosingUnit.linkedContext.isLate(linkedNode);
-// }
-// if (_unlinkedVariable != null) {
-// return _unlinkedVariable.isLate;
-// }
- return hasModifier(Modifier.LATE);
- }
-
- @override
bool get isStatic {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isStatic(linkedNode);
@@ -7080,12 +7069,12 @@
@override
bool get isLate {
-// if (linkedNode != null) {
-// return enclosingUnit.linkedContext.isLate(linkedNode);
-// }
-// if (_unlinkedVariable != null) {
-// return _unlinkedVariable.isLate;
-// }
+ if (linkedNode != null) {
+ return enclosingUnit.linkedContext.isLate(linkedNode);
+ }
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.isLate;
+ }
return hasModifier(Modifier.LATE);
}
@@ -9039,6 +9028,17 @@
@override
bool get isConstantEvaluated => true;
+ @override
+ bool get isLate {
+ if (linkedNode != null) {
+ return enclosingUnit.linkedContext.isLate(linkedNode);
+ }
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.isLate;
+ }
+ return hasModifier(Modifier.LATE);
+ }
+
@deprecated
@override
DartType get propagatedType => null;
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index 7f7f58f..f316eb7 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -667,9 +667,6 @@
@override
bool get isEnumConstant => actualElement.isEnumConstant;
- @override
- bool get isLate => actualElement.isLate;
-
@deprecated
@override
bool get isVirtual => actualElement.isVirtual;
@@ -1183,6 +1180,9 @@
@override
bool get isConstantEvaluated => actualElement.isConstantEvaluated;
+ @override
+ bool get isLate => actualElement.isLate;
+
@deprecated
@override
DartType get propagatedType => null;
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 5a7bf2e..5c52ba4 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -29209,6 +29209,7 @@
bool _isConst;
bool _isCovariant;
bool _isFinal;
+ bool _isLate;
bool _isStatic;
String _name;
int _nameOffset;
@@ -29303,6 +29304,14 @@
}
@override
+ bool get isLate => _isLate ??= false;
+
+ /// Indicates whether the variable is declared using the `late` keyword.
+ set isLate(bool value) {
+ this._isLate = value;
+ }
+
+ @override
bool get isStatic => _isStatic ??= false;
/// Indicates whether the variable is declared using the `static` keyword.
@@ -29371,6 +29380,7 @@
bool isConst,
bool isCovariant,
bool isFinal,
+ bool isLate,
bool isStatic,
String name,
int nameOffset,
@@ -29385,6 +29395,7 @@
_isConst = isConst,
_isCovariant = isCovariant,
_isFinal = isFinal,
+ _isLate = isLate,
_isStatic = isStatic,
_name = name,
_nameOffset = nameOffset,
@@ -29423,6 +29434,7 @@
this._initializer?.collectApiSignature(signature);
signature.addBool(this._isCovariant == true);
signature.addInt(this._inheritsCovariantSlot ?? 0);
+ signature.addBool(this._isLate == true);
}
fb.Offset finish(fb.Builder fbBuilder) {
@@ -29479,6 +29491,9 @@
if (_isFinal == true) {
fbBuilder.addBool(7, true);
}
+ if (_isLate == true) {
+ fbBuilder.addBool(16, true);
+ }
if (_isStatic == true) {
fbBuilder.addBool(4, true);
}
@@ -29523,6 +29538,7 @@
bool _isConst;
bool _isCovariant;
bool _isFinal;
+ bool _isLate;
bool _isStatic;
String _name;
int _nameOffset;
@@ -29590,6 +29606,12 @@
}
@override
+ bool get isLate {
+ _isLate ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 16, false);
+ return _isLate;
+ }
+
+ @override
bool get isStatic {
_isStatic ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 4, false);
return _isStatic;
@@ -29646,6 +29668,7 @@
if (isConst != false) _result["isConst"] = isConst;
if (isCovariant != false) _result["isCovariant"] = isCovariant;
if (isFinal != false) _result["isFinal"] = isFinal;
+ if (isLate != false) _result["isLate"] = isLate;
if (isStatic != false) _result["isStatic"] = isStatic;
if (name != '') _result["name"] = name;
if (nameOffset != 0) _result["nameOffset"] = nameOffset;
@@ -29666,6 +29689,7 @@
"isConst": isConst,
"isCovariant": isCovariant,
"isFinal": isFinal,
+ "isLate": isLate,
"isStatic": isStatic,
"name": name,
"nameOffset": nameOffset,
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index b38bb03..f0c47f5 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -3122,6 +3122,9 @@
/// Indicates whether the variable is declared using the `final` keyword.
isFinal:bool (id: 7);
+ /// Indicates whether the variable is declared using the `late` keyword.
+ isLate:bool (id: 16);
+
/// Indicates whether the variable is declared using the `static` keyword.
///
/// Note that for top level variables, this flag is false, since they are not
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 69e924f..3ea8752 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -4875,6 +4875,10 @@
@Id(7)
bool get isFinal;
+ /// Indicates whether the variable is declared using the `late` keyword.
+ @Id(16)
+ bool get isLate;
+
/// Indicates whether the variable is declared using the `static` keyword.
///
/// Note that for top level variables, this flag is false, since they are not
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 8a2139b..9723dd5 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -2577,6 +2577,9 @@
initializerForInference);
@override
+ bool get isLate => unlinkedVariable.isLate;
+
+ @override
bool get isStatic => unlinkedVariable.isStatic;
@override
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index 34b2ff1..464c4a7 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -1004,6 +1004,7 @@
b.isConst = variables.isConst;
b.isCovariant = isCovariant;
b.isFinal = variables.isFinal;
+ b.isLate = variable.isLate;
b.isStatic = isDeclaredStatic;
b.name = variable.name.name;
b.nameOffset = variable.name.offset;
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 4f75fd8..c5e0078 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -819,6 +819,19 @@
}
}
+ bool isLate(AstNode node) {
+ if (node is VariableDeclaration) {
+ return node.isLate;
+ }
+ if (node is VariableDeclarationList) {
+ return node.isLate;
+ }
+ if (node is EnumConstantDeclaration) {
+ return false;
+ }
+ throw UnimplementedError('${node.runtimeType}');
+ }
+
bool isLibraryKeyword(int token) {
return tokensContext.type(token) == UnlinkedTokenType.LIBRARY;
}
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index f923d30..cde7dc7 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -886,6 +886,7 @@
writeMetadata(e, '', '\n');
}
+ writeIf(e.isLate, 'late ');
writeIf(e.isFinal, 'final ');
writeIf(e.isConst, 'const ');
writeType2(type);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 7ec7d23..56fc949 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -110,6 +110,26 @@
return elementFactory.libraryOfUri('${source.uri}');
}
+ @failingTest
+ test_class_field_const_late() async {
+ await super.test_class_field_const_late();
+ }
+
+ @failingTest
+ test_class_field_implicit_type_late() async {
+ await super.test_class_field_implicit_type_late();
+ }
+
+ @failingTest
+ test_class_field_static_late() async {
+ await super.test_class_field_static_late();
+ }
+
+ @failingTest
+ test_class_fields_late() async {
+ await super.test_class_fields_late();
+ }
+
@override
@failingTest
test_const_constructor_inferred_args() async {
@@ -130,6 +150,21 @@
await super.test_syntheticFunctionType_genericClosure();
}
+ @failingTest
+ test_variable_const_late() async {
+ await super.test_variable_const_late();
+ }
+
+ @failingTest
+ test_variable_final_late() async {
+ await super.test_variable_final_late();
+ }
+
+ @failingTest
+ test_variable_late() async {
+ await super.test_variable_late();
+ }
+
void _addLibraryUnits(
Source definingSource,
CompilationUnit definingUnit,
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 70ecb30..b4acb72 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -10,8 +10,8 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(ResynthesizeAstStrongTest);
defineReflectiveTests(ApplyCheckElementTextReplacements);
+ defineReflectiveTests(ResynthesizeAstStrongTest);
});
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 585b9a5c..07d58d9 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import 'package:analyzer/dart/analysis/declared_variables.dart';
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -1000,6 +1001,18 @@
''');
}
+ test_class_field_const_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library =
+ await checkLibrary('class C { late static const int i = 0; }');
+ checkElementText(library, r'''
+class C {
+ static late const int i = 0;
+}
+''');
+ }
+
test_class_field_implicit_type() async {
var library = await checkLibrary('class C { var x; }');
checkElementText(library, r'''
@@ -1009,6 +1022,17 @@
''');
}
+ test_class_field_implicit_type_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library = await checkLibrary('class C { late var x; }');
+ checkElementText(library, r'''
+class C {
+ late dynamic x;
+}
+''');
+ }
+
test_class_field_static() async {
var library = await checkLibrary('class C { static int i; }');
checkElementText(library, r'''
@@ -1018,6 +1042,17 @@
''');
}
+ test_class_field_static_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library = await checkLibrary('class C { late static int i; }');
+ checkElementText(library, r'''
+class C {
+ static late int i;
+}
+''');
+ }
+
test_class_fields() async {
var library = await checkLibrary('class C { int i; int j; }');
checkElementText(library, r'''
@@ -1028,6 +1063,18 @@
''');
}
+ test_class_fields_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library = await checkLibrary('class C { int i; late int j; }');
+ checkElementText(library, r'''
+class C {
+ int i;
+ late int j;
+}
+''');
+ }
+
test_class_getter_abstract() async {
var library = await checkLibrary('abstract class C { int get x; }');
checkElementText(library, r'''
@@ -9850,6 +9897,15 @@
''');
}
+ test_variable_const_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library = await checkLibrary('late const int i = 0;');
+ checkElementText(library, r'''
+late const int i = 0;
+''');
+ }
+
test_variable_documented() async {
var library = await checkLibrary('''
// Extra comment so doc comment offset != 0
@@ -9872,6 +9928,15 @@
''');
}
+ test_variable_final_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library = await checkLibrary('late final int x = 0;');
+ checkElementText(library, r'''
+late final int x;
+''');
+ }
+
test_variable_getterInLib_setterInPart() async {
addSource('/a.dart', '''
part of my.lib;
@@ -9975,6 +10040,15 @@
''');
}
+ test_variable_late() async {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ var library = await checkLibrary('late int x = 0;');
+ checkElementText(library, r'''
+late int x;
+''');
+ }
+
test_variable_propagatedType_const_noDep() async {
var library = await checkLibrary('const i = 0;');
checkElementText(library, r'''
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 5d79e38..1e762b5 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -8597,6 +8597,7 @@
UnlinkedVariable variable = findVariable('i', variables: cls.fields);
expect(variable, isNotNull);
expect(variable.isConst, isFalse);
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isFalse);
expect(variable.isFinal, isFalse);
expect(variable.initializer, isNull);
@@ -8869,6 +8870,7 @@
test_field_static() {
UnlinkedVariable variable =
serializeClassText('class C { static int i; }').fields[0];
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isTrue);
expect(variable.initializer, isNull);
expect(variable.inheritsCovariantSlot, 0);
@@ -8888,6 +8890,7 @@
test_field_static_final() {
UnlinkedVariable variable =
serializeClassText('class C { static final int i = 0; }').fields[0];
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isTrue);
expect(variable.isFinal, isTrue);
expect(variable.initializer.bodyExpr, isNull);
@@ -11737,6 +11740,7 @@
test_variable_no_flags() {
UnlinkedVariable variable =
serializeVariableText('int i;', variableName: 'i');
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isFalse);
expect(variable.isConst, isFalse);
expect(variable.isFinal, isFalse);
@@ -11757,6 +11761,7 @@
test_variable_non_static() {
UnlinkedVariable variable =
serializeClassText('class C { int i; }').fields[0];
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isFalse);
}
@@ -11764,6 +11769,7 @@
// Top level variables are considered non-static.
UnlinkedVariable variable =
serializeVariableText('int i;', variableName: 'i');
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isFalse);
}
@@ -11775,6 +11781,7 @@
test_variable_static() {
UnlinkedVariable variable =
serializeClassText('class C { static int i; }').fields[0];
+ expect(variable.isLate, isFalse);
expect(variable.isStatic, isTrue);
}
@@ -11884,6 +11891,71 @@
var expression = body.expression;
return tokensToString(expression.beginToken, expression.endToken);
}
+
+ test_field_late() {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ UnlinkedClass cls = serializeClassText('class C { late int i; }');
+ UnlinkedVariable variable = findVariable('i', variables: cls.fields);
+ expect(variable, isNotNull);
+ expect(variable.isConst, isFalse);
+ expect(variable.isLate, isTrue);
+ expect(variable.isStatic, isFalse);
+ expect(variable.isFinal, isFalse);
+ expect(variable.initializer, isNull);
+ expect(variable.inheritsCovariantSlot, isNot(0));
+ expect(findExecutable('i', executables: cls.executables), isNull);
+ expect(findExecutable('i=', executables: cls.executables), isNull);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+ expect(unlinkedUnits[0].publicNamespace.names[0].members, isEmpty);
+ }
+
+ test_field_static_final_late() {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ UnlinkedVariable variable =
+ serializeClassText('class C { static late final int i = 0; }')
+ .fields[0];
+ expect(variable.isLate, isTrue);
+ expect(variable.isStatic, isTrue);
+ expect(variable.isFinal, isTrue);
+ expect(variable.initializer.bodyExpr, isNull);
+ expect(variable.inheritsCovariantSlot, 0);
+ }
+
+ test_field_static_late() {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ UnlinkedVariable variable =
+ serializeClassText('class C { late static int i; }').fields[0];
+ expect(variable.isLate, isTrue);
+ expect(variable.isStatic, isTrue);
+ expect(variable.initializer, isNull);
+ expect(variable.inheritsCovariantSlot, 0);
+ expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+ expect(unlinkedUnits[0].publicNamespace.names[0].members, hasLength(1));
+ expect(unlinkedUnits[0].publicNamespace.names[0].members[0].name, 'i');
+ expect(unlinkedUnits[0].publicNamespace.names[0].members[0].kind,
+ ReferenceKind.propertyAccessor);
+ expect(
+ unlinkedUnits[0].publicNamespace.names[0].members[0].numTypeParameters,
+ 0);
+ expect(
+ unlinkedUnits[0].publicNamespace.names[0].members[0].members, isEmpty);
+ }
+
+ test_variable_late() {
+ experimentStatus = FeatureSet.forTesting(
+ sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]);
+ UnlinkedVariable variable =
+ serializeVariableText('late int i;', variableName: 'i');
+ expect(variable.isLate, isTrue);
+ expect(variable.isStatic, isFalse);
+ expect(variable.isConst, isFalse);
+ expect(variable.isFinal, isFalse);
+ }
}
/**