[_fe_analyzer_shared] Support deferencing of StaticGet
This adds support for replacement a [StaticGet] with the constant
initializer of the referenced constant during evaluation of macro
metadata. Currently constants defined in the same library or
compilation is supported. For full support the constant initializers
need to be included in the outlines/summaries.
Change-Id: I219f85dded63342d4e3f957f0b7321badbe376a4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392907
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/metadata/evaluate.dart b/pkg/_fe_analyzer_shared/lib/src/metadata/evaluate.dart
index 050c7be..a85ed79 100644
--- a/pkg/_fe_analyzer_shared/lib/src/metadata/evaluate.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/metadata/evaluate.dart
@@ -4,13 +4,39 @@
import 'ast.dart';
+typedef GetFieldInitializer = Expression? Function(
+ FieldReference fieldReference);
+
/// Evaluates an [expression] based on the semantics that can be deduced from
/// the syntax.
-Expression evaluateExpression(Expression expression) {
- return new Evaluator().evaluate(expression);
+///
+/// If [getFieldInitializer] is provided, it is used to get constant initializer
+/// expressions of const [StaticGet]s in [expression]. The evaluated constant
+/// initializer expressions are used as the evaluation result of the
+/// [StaticGet]s.
+///
+/// If [dereferences] is provided, the field references of [StaticGet]s, for
+/// which [getFieldInitializer] has provided a constant initializer
+/// [Expression], are mapped to there corresponding in constant initializer
+/// [Expression]s in [dereferences].
+Expression evaluateExpression(Expression expression,
+ {GetFieldInitializer? getFieldInitializer,
+ Map<FieldReference, Expression>? dereferences}) {
+ return new Evaluator(
+ getFieldInitializer: getFieldInitializer, dereferences: dereferences)
+ .evaluate(expression);
}
class Evaluator {
+ final GetFieldInitializer? _getFieldInitializer;
+ final Map<FieldReference, Expression>? _dereferences;
+
+ Evaluator(
+ {required GetFieldInitializer? getFieldInitializer,
+ required Map<FieldReference, Expression>? dereferences})
+ : _getFieldInitializer = getFieldInitializer,
+ _dereferences = dereferences;
+
Expression evaluate(Expression expression) {
return _visitExpression(expression);
}
@@ -18,7 +44,15 @@
Expression _visitExpression(Expression expression) {
switch (expression) {
case StaticGet():
- // TODO(johnniwinther): Support inlining constant values.
+ if (_getFieldInitializer != null) {
+ Expression? result = _getFieldInitializer(expression.reference);
+ if (result != null) {
+ if (_dereferences != null) {
+ _dereferences[expression.reference] = result;
+ }
+ return _visitExpression(result);
+ }
+ }
return expression;
case InvalidExpression():
case FunctionTearOff():
diff --git a/pkg/_fe_analyzer_shared/lib/src/metadata/parser.dart b/pkg/_fe_analyzer_shared/lib/src/metadata/parser.dart
index b8df2c2..42a72b7 100644
--- a/pkg/_fe_analyzer_shared/lib/src/metadata/parser.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/metadata/parser.dart
@@ -1053,6 +1053,18 @@
return listener.pop() as Expression;
}
+/// Parses the expression beginning at [initializerToken].
+Expression parseExpression(
+ Token initializerToken, Uri fileUri, Scope scope, References references,
+ {required bool isDartLibrary, bool delayLookupForTesting = false}) {
+ AnnotationsListener listener = new AnnotationsListener(
+ fileUri, scope, references,
+ delayLookup: delayLookupForTesting, isDartLibrary: isDartLibrary);
+ Parser parser = new Parser(listener, useImplicitCreationExpression: false);
+ parser.parseExpression(parser.syntheticPreviousToken(initializerToken));
+ return listener._popExpression();
+}
+
/// A [Scope] extended to include function type parameters.
class FunctionTypeParameterScope implements Scope {
final Scope parentScope;
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/metadata_helper.dart b/pkg/_fe_analyzer_shared/lib/src/testing/metadata_helper.dart
index ebbf160..d6338de 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/metadata_helper.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/metadata_helper.dart
@@ -27,13 +27,23 @@
/// Creates a list containing structured and readable textual representation of
/// the [resolved] expression and the result of evaluating [resolved].
-List<String> evaluationToText(Expression resolved) {
+///
+/// If [getFieldInitializer] is provided, it is used to dereference constant
+/// field references during evaluation.
+List<String> evaluationToText(Expression resolved,
+ {GetFieldInitializer? getFieldInitializer}) {
List<String> list = [];
Expression unwrappedResolved = unwrap(resolved);
list.add('resolved=${expressionToText(unwrappedResolved)}');
- list.add(
- 'evaluate=${expressionToText(evaluateExpression(unwrappedResolved))}');
+
+ Map<FieldReference, Expression> dereferences = {};
+ Expression evaluated = evaluateExpression(unwrappedResolved,
+ getFieldInitializer: getFieldInitializer, dereferences: dereferences);
+ list.add('evaluate=${expressionToText(evaluated)}');
+ for (MapEntry<FieldReference, Expression> entry in dereferences.entries) {
+ list.add('${entry.key.name}=${expressionToText(entry.value)}');
+ }
return list;
}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/binary.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/binary.dart
index 6e5d48b..1a0550d 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/binary.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/binary.dart
@@ -125,5 +125,6 @@
@Helper(1 + constInt)
/*member: binary20:
resolved=BinaryExpression(IntegerLiteral(1) + StaticGet(constInt))
-evaluate=BinaryExpression(IntegerLiteral(1) + StaticGet(constInt))*/
+evaluate=IntegerLiteral(value=43)
+constInt=IntegerLiteral(42)*/
void binary20() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/equality.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/equality.dart
index a319c62..f2e0def 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/equality.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/equality.dart
@@ -47,12 +47,14 @@
@Helper(constInt == 1)
/*member: equalityExpression7:
resolved=EqualityExpression(StaticGet(constInt) == IntegerLiteral(1))
-evaluate=EqualityExpression(StaticGet(constInt) == IntegerLiteral(1))*/
+evaluate=BooleanLiteral(false)
+constInt=IntegerLiteral(42)*/
void equalityExpression7() {}
@Helper(constInt != 1)
/*member: equalityExpression8:
resolved=EqualityExpression(StaticGet(constInt) != IntegerLiteral(1))
-evaluate=EqualityExpression(StaticGet(constInt) != IntegerLiteral(1))*/
+evaluate=BooleanLiteral(true)
+constInt=IntegerLiteral(42)*/
void equalityExpression8() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/if_null.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/if_null.dart
index 1ca9ccc..319eee2 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/if_null.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/if_null.dart
@@ -55,9 +55,6 @@
??
IntegerLiteral(0)
)
-evaluate=IfNull(
- StaticGet(constNullableInt)
- ??
- IntegerLiteral(0)
-)*/
+evaluate=IntegerLiteral(42)
+constNullableInt=IntegerLiteral(42)*/
void ifNull5() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/list_literal.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/list_literal.dart
index 4c39943..f7cab95 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/list_literal.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/list_literal.dart
@@ -33,7 +33,8 @@
@Helper([?constInt])
/*member: listLiteral4:
resolved=ListLiteral([ExpressionElement(?StaticGet(constInt))])
-evaluate=ListLiteral([ExpressionElement(?StaticGet(constInt))])*/
+evaluate=ListLiteral([ExpressionElement(IntegerLiteral(42))])
+constInt=IntegerLiteral(42)*/
void listLiteral4() {}
@Helper([if (true) 1])
@@ -57,9 +58,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
ExpressionElement(IntegerLiteral(1)))])
-evaluate=ListLiteral([IfElement(
- StaticGet(constBool),
- ExpressionElement(IntegerLiteral(1)))])*/
+evaluate=ListLiteral([ExpressionElement(IntegerLiteral(1))])
+constBool=BooleanLiteral(true)*/
void listLiteral7() {}
@Helper([if (true) 1 else 2])
@@ -86,10 +86,8 @@
StaticGet(constBool),
ExpressionElement(IntegerLiteral(1)),
ExpressionElement(IntegerLiteral(2)))])
-evaluate=ListLiteral([IfElement(
- StaticGet(constBool),
- ExpressionElement(IntegerLiteral(1)),
- ExpressionElement(IntegerLiteral(2)))])*/
+evaluate=ListLiteral([ExpressionElement(IntegerLiteral(1))])
+constBool=BooleanLiteral(true)*/
void listLiteral10() {}
@Helper([...[0, 1]])
@@ -105,7 +103,12 @@
@Helper([...constList])
/*member: listLiteral12:
resolved=ListLiteral([SpreadElement(...StaticGet(constList))])
-evaluate=ListLiteral([SpreadElement(...StaticGet(constList))])*/
+evaluate=ListLiteral([
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))])
+constList=ListLiteral([
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))])*/
void listLiteral12() {}
@Helper([...?[0, 1]])
@@ -121,7 +124,12 @@
@Helper([...?constList])
/*member: listLiteral14:
resolved=ListLiteral([SpreadElement(?...StaticGet(constList))])
-evaluate=ListLiteral([SpreadElement(?...StaticGet(constList))])*/
+evaluate=ListLiteral([
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))])
+constList=ListLiteral([
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))])*/
void listLiteral14() {}
@Helper([...?null])
@@ -135,7 +143,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
ExpressionElement(?NullLiteral()))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral16() {}
@Helper([if (constBool) ?null else 2])
@@ -144,9 +153,8 @@
StaticGet(constBool),
ExpressionElement(?NullLiteral()),
ExpressionElement(IntegerLiteral(2)))])
-evaluate=ListLiteral([IfElement(
- UnaryExpression(!StaticGet(constBool)),
- ExpressionElement(IntegerLiteral(2)))])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral17() {}
@Helper([if (constBool) 1 else ?null])
@@ -155,9 +163,8 @@
StaticGet(constBool),
ExpressionElement(IntegerLiteral(1)),
ExpressionElement(?NullLiteral()))])
-evaluate=ListLiteral([IfElement(
- StaticGet(constBool),
- ExpressionElement(IntegerLiteral(1)))])*/
+evaluate=ListLiteral([ExpressionElement(IntegerLiteral(1))])
+constBool=BooleanLiteral(true)*/
void listLiteral18() {}
@Helper([if (constBool) ?null else ?null])
@@ -166,7 +173,8 @@
StaticGet(constBool),
ExpressionElement(?NullLiteral()),
ExpressionElement(?NullLiteral()))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral19() {}
@Helper([if (constBool) ...[]])
@@ -174,7 +182,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
SpreadElement(...ListLiteral([])))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral20() {}
@Helper([if (constBool) ...{}])
@@ -182,7 +191,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
SpreadElement(...SetOrMapLiteral({})))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral21() {}
@Helper([if (constBool) ...?[]])
@@ -190,7 +200,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
SpreadElement(?...ListLiteral([])))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral22() {}
@Helper([if (constBool) ...?{}])
@@ -198,7 +209,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
SpreadElement(?...SetOrMapLiteral({})))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral23() {}
@Helper([if (constBool) ...?null])
@@ -206,7 +218,8 @@
resolved=ListLiteral([IfElement(
StaticGet(constBool),
SpreadElement(?...NullLiteral()))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)*/
void listLiteral24() {}
@Helper([if (constBool) if (constBool) ?null else ?null])
@@ -217,5 +230,7 @@
StaticGet(constBool),
ExpressionElement(?NullLiteral()),
ExpressionElement(?NullLiteral())))])
-evaluate=ListLiteral([])*/
+evaluate=ListLiteral([])
+constBool=BooleanLiteral(true)
+constBool=BooleanLiteral(true)*/
void listLiteral25() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/logical.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/logical.dart
index a604500..b77d6d0 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/logical.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/logical.dart
@@ -59,23 +59,27 @@
@Helper(constBool && true)
/*member: logicalExpression9:
resolved=LogicalExpression(StaticGet(constBool) && BooleanLiteral(true))
-evaluate=LogicalExpression(StaticGet(constBool) && BooleanLiteral(true))*/
+evaluate=BooleanLiteral(true)
+constBool=BooleanLiteral(true)*/
void logicalExpression9() {}
@Helper(constBool && false)
/*member: logicalExpression10:
resolved=LogicalExpression(StaticGet(constBool) && BooleanLiteral(false))
-evaluate=LogicalExpression(StaticGet(constBool) && BooleanLiteral(false))*/
+evaluate=BooleanLiteral(false)
+constBool=BooleanLiteral(true)*/
void logicalExpression10() {}
@Helper(constBool || true)
/*member: logicalExpression11:
resolved=LogicalExpression(StaticGet(constBool) || BooleanLiteral(true))
-evaluate=LogicalExpression(StaticGet(constBool) || BooleanLiteral(true))*/
+evaluate=BooleanLiteral(true)
+constBool=BooleanLiteral(true)*/
void logicalExpression11() {}
@Helper(constBool || false)
/*member: logicalExpression12:
resolved=LogicalExpression(StaticGet(constBool) || BooleanLiteral(false))
-evaluate=LogicalExpression(StaticGet(constBool) || BooleanLiteral(false))*/
+evaluate=BooleanLiteral(true)
+constBool=BooleanLiteral(true)*/
void logicalExpression12() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/null_check.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/null_check.dart
index d8b06a0..25d04c3 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/null_check.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/null_check.dart
@@ -23,5 +23,6 @@
@Helper(constInt!)
/*member: nullCheck3:
resolved=NullCheck(StaticGet(constInt))
-evaluate=NullCheck(StaticGet(constInt))*/
+evaluate=IntegerLiteral(42)
+constInt=IntegerLiteral(42)*/
void nullCheck3() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/set_or_map_literal.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/set_or_map_literal.dart
index 34efa4b..835d269 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/set_or_map_literal.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/set_or_map_literal.dart
@@ -33,7 +33,8 @@
@Helper({?constInt})
/*member: setOrMapLiteral4:
resolved=SetOrMapLiteral({ExpressionElement(?StaticGet(constInt))})
-evaluate=SetOrMapLiteral({ExpressionElement(?StaticGet(constInt))})*/
+evaluate=SetOrMapLiteral({ExpressionElement(IntegerLiteral(42))})
+constInt=IntegerLiteral(42)*/
void setOrMapLiteral4() {}
@Helper({if (true) 1})
@@ -57,9 +58,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
ExpressionElement(IntegerLiteral(1)))})
-evaluate=SetOrMapLiteral({IfElement(
- StaticGet(constBool),
- ExpressionElement(IntegerLiteral(1)))})*/
+evaluate=SetOrMapLiteral({ExpressionElement(IntegerLiteral(1))})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral7() {}
@Helper({if (true) 1 else 2})
@@ -86,10 +86,8 @@
StaticGet(constBool),
ExpressionElement(IntegerLiteral(1)),
ExpressionElement(IntegerLiteral(2)))})
-evaluate=SetOrMapLiteral({IfElement(
- StaticGet(constBool),
- ExpressionElement(IntegerLiteral(1)),
- ExpressionElement(IntegerLiteral(2)))})*/
+evaluate=SetOrMapLiteral({ExpressionElement(IntegerLiteral(1))})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral10() {}
@Helper({...{0, 1}})
@@ -105,7 +103,12 @@
@Helper({...constList})
/*member: setOrMapLiteral12:
resolved=SetOrMapLiteral({SpreadElement(...StaticGet(constList))})
-evaluate=SetOrMapLiteral({SpreadElement(...StaticGet(constList))})*/
+evaluate=SetOrMapLiteral({
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))})
+constList=ListLiteral([
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))])*/
void setOrMapLiteral12() {}
@Helper({...?{0, 1}})
@@ -121,7 +124,12 @@
@Helper({...?constList})
/*member: setOrMapLiteral14:
resolved=SetOrMapLiteral({SpreadElement(?...StaticGet(constList))})
-evaluate=SetOrMapLiteral({SpreadElement(?...StaticGet(constList))})*/
+evaluate=SetOrMapLiteral({
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))})
+constList=ListLiteral([
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3))])*/
void setOrMapLiteral14() {}
@Helper({...?null})
@@ -135,7 +143,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
ExpressionElement(?NullLiteral()))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral16() {}
@Helper({if (constBool) ?null else 2})
@@ -144,9 +153,8 @@
StaticGet(constBool),
ExpressionElement(?NullLiteral()),
ExpressionElement(IntegerLiteral(2)))})
-evaluate=SetOrMapLiteral({IfElement(
- UnaryExpression(!StaticGet(constBool)),
- ExpressionElement(IntegerLiteral(2)))})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral17() {}
@Helper({if (constBool) 1 else ?null})
@@ -155,9 +163,8 @@
StaticGet(constBool),
ExpressionElement(IntegerLiteral(1)),
ExpressionElement(?NullLiteral()))})
-evaluate=SetOrMapLiteral({IfElement(
- StaticGet(constBool),
- ExpressionElement(IntegerLiteral(1)))})*/
+evaluate=SetOrMapLiteral({ExpressionElement(IntegerLiteral(1))})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral18() {}
@Helper({if (constBool) ?null else ?null})
@@ -166,7 +173,8 @@
StaticGet(constBool),
ExpressionElement(?NullLiteral()),
ExpressionElement(?NullLiteral()))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral19() {}
@Helper({if (constBool) ...[]})
@@ -174,7 +182,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
SpreadElement(...ListLiteral([])))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral20() {}
@Helper({if (constBool) ...[]})
@@ -182,7 +191,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
SpreadElement(...ListLiteral([])))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral21() {}
@Helper({if (constBool) ...?{}})
@@ -190,7 +200,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
SpreadElement(?...SetOrMapLiteral({})))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral22() {}
@Helper({if (constBool) ...?{}})
@@ -198,7 +209,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
SpreadElement(?...SetOrMapLiteral({})))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral23() {}
@Helper({if (constBool) ...?null})
@@ -206,7 +218,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
SpreadElement(?...NullLiteral()))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral24() {}
@Helper({if (constBool) if (constBool) ?null else ?null})
@@ -217,7 +230,9 @@
StaticGet(constBool),
ExpressionElement(?NullLiteral()),
ExpressionElement(?NullLiteral())))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral25() {}
@Helper({0: 1})
@@ -265,19 +280,23 @@
@Helper({?constInt: 1})
/*member: setOrMapLiteral33:
resolved=SetOrMapLiteral({MapEntryElement(?StaticGet(constInt):IntegerLiteral(1))})
-evaluate=SetOrMapLiteral({MapEntryElement(?StaticGet(constInt):IntegerLiteral(1))})*/
+evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(42):IntegerLiteral(1))})
+constInt=IntegerLiteral(42)*/
void setOrMapLiteral33() {}
@Helper({0: ?constInt})
/*member: setOrMapLiteral34:
resolved=SetOrMapLiteral({MapEntryElement(IntegerLiteral(0):?StaticGet(constInt))})
-evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(0):?StaticGet(constInt))})*/
+evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(0):IntegerLiteral(42))})
+constInt=IntegerLiteral(42)*/
void setOrMapLiteral34() {}
@Helper({?constInt: ?constInt})
/*member: setOrMapLiteral35:
resolved=SetOrMapLiteral({MapEntryElement(?StaticGet(constInt):?StaticGet(constInt))})
-evaluate=SetOrMapLiteral({MapEntryElement(?StaticGet(constInt):?StaticGet(constInt))})*/
+evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(42):IntegerLiteral(42))})
+constInt=IntegerLiteral(42)
+constInt=IntegerLiteral(42)*/
void setOrMapLiteral35() {}
@Helper({if (constBool) ?null: 1})
@@ -285,7 +304,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
MapEntryElement(?NullLiteral():IntegerLiteral(1)))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral36() {}
@Helper({if (constBool) 0: ?null})
@@ -293,7 +313,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
MapEntryElement(IntegerLiteral(0):?NullLiteral()))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral37() {}
@Helper({if (constBool) ?null: ?null})
@@ -301,7 +322,8 @@
resolved=SetOrMapLiteral({IfElement(
StaticGet(constBool),
MapEntryElement(?NullLiteral():?NullLiteral()))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral38() {}
@Helper({if (constBool) ?null: 1 else 2: 3})
@@ -310,9 +332,8 @@
StaticGet(constBool),
MapEntryElement(?NullLiteral():IntegerLiteral(1)),
MapEntryElement(IntegerLiteral(2):IntegerLiteral(3)))})
-evaluate=SetOrMapLiteral({IfElement(
- UnaryExpression(!StaticGet(constBool)),
- MapEntryElement(IntegerLiteral(2):IntegerLiteral(3)))})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral39() {}
@Helper({if (constBool) 0: ?null else 2: 3})
@@ -321,9 +342,8 @@
StaticGet(constBool),
MapEntryElement(IntegerLiteral(0):?NullLiteral()),
MapEntryElement(IntegerLiteral(2):IntegerLiteral(3)))})
-evaluate=SetOrMapLiteral({IfElement(
- UnaryExpression(!StaticGet(constBool)),
- MapEntryElement(IntegerLiteral(2):IntegerLiteral(3)))})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral40() {}
@Helper({if (constBool) ?null: ?null else 2: 3})
@@ -332,9 +352,8 @@
StaticGet(constBool),
MapEntryElement(?NullLiteral():?NullLiteral()),
MapEntryElement(IntegerLiteral(2):IntegerLiteral(3)))})
-evaluate=SetOrMapLiteral({IfElement(
- UnaryExpression(!StaticGet(constBool)),
- MapEntryElement(IntegerLiteral(2):IntegerLiteral(3)))})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral41() {}
@Helper({if (constBool) 1: 2 else ?null: 3})
@@ -343,9 +362,8 @@
StaticGet(constBool),
MapEntryElement(IntegerLiteral(1):IntegerLiteral(2)),
MapEntryElement(?NullLiteral():IntegerLiteral(3)))})
-evaluate=SetOrMapLiteral({IfElement(
- StaticGet(constBool),
- MapEntryElement(IntegerLiteral(1):IntegerLiteral(2)))})*/
+evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(1):IntegerLiteral(2))})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral42() {}
@Helper({if (constBool) 1: 2 else 3: ?null})
@@ -354,9 +372,8 @@
StaticGet(constBool),
MapEntryElement(IntegerLiteral(1):IntegerLiteral(2)),
MapEntryElement(IntegerLiteral(3):?NullLiteral()))})
-evaluate=SetOrMapLiteral({IfElement(
- StaticGet(constBool),
- MapEntryElement(IntegerLiteral(1):IntegerLiteral(2)))})*/
+evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(1):IntegerLiteral(2))})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral43() {}
@Helper({if (constBool) 1: 2 else ?null: ?null})
@@ -365,9 +382,8 @@
StaticGet(constBool),
MapEntryElement(IntegerLiteral(1):IntegerLiteral(2)),
MapEntryElement(?NullLiteral():?NullLiteral()))})
-evaluate=SetOrMapLiteral({IfElement(
- StaticGet(constBool),
- MapEntryElement(IntegerLiteral(1):IntegerLiteral(2)))})*/
+evaluate=SetOrMapLiteral({MapEntryElement(IntegerLiteral(1):IntegerLiteral(2))})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral44() {}
@Helper({if (constBool) ?null: 1 else ?null: 2})
@@ -376,7 +392,8 @@
StaticGet(constBool),
MapEntryElement(?NullLiteral():IntegerLiteral(1)),
MapEntryElement(?NullLiteral():IntegerLiteral(2)))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral45() {}
@Helper({if (constBool) 1: ?null else 2: ?null})
@@ -385,5 +402,6 @@
StaticGet(constBool),
MapEntryElement(IntegerLiteral(1):?NullLiteral()),
MapEntryElement(IntegerLiteral(2):?NullLiteral()))})
-evaluate=SetOrMapLiteral({})*/
+evaluate=SetOrMapLiteral({})
+constBool=BooleanLiteral(true)*/
void setOrMapLiteral46() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/spread.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/spread.dart
new file mode 100644
index 0000000..4b8e4f4a
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/spread.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2024, 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.
+
+class Helper {
+ const Helper(a);
+}
+
+const a = 0;
+const b = [a, 1, 2];
+const c = [...b, 3, 4];
+
+class Class {
+ const Class(values);
+}
+
+@Class([-1, ...c, 5, 6])
+/*member: spread1:
+resolved=ConstructorInvocation(
+ Class.new(ListLiteral([
+ ExpressionElement(UnaryExpression(-IntegerLiteral(1))),
+ SpreadElement(...StaticGet(c)),
+ ExpressionElement(IntegerLiteral(5)),
+ ExpressionElement(IntegerLiteral(6))])))
+evaluate=ConstructorInvocation(
+ Class.new(ListLiteral([
+ ExpressionElement(IntegerLiteral(value=-1)),
+ ExpressionElement(IntegerLiteral(0)),
+ ExpressionElement(IntegerLiteral(1)),
+ ExpressionElement(IntegerLiteral(2)),
+ ExpressionElement(IntegerLiteral(3)),
+ ExpressionElement(IntegerLiteral(4)),
+ ExpressionElement(IntegerLiteral(5)),
+ ExpressionElement(IntegerLiteral(6))])))
+c=ListLiteral([
+ SpreadElement(...StaticGet(b)),
+ ExpressionElement(IntegerLiteral(3)),
+ ExpressionElement(IntegerLiteral(4))])
+b=ListLiteral([
+ ExpressionElement(StaticGet(a)),
+ ExpressionElement(IntegerLiteral(1)),
+ ExpressionElement(IntegerLiteral(2))])
+a=IntegerLiteral(0)*/
+void spread1() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/string_interpolation.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/string_interpolation.dart
index aeb1e8f..ff38d8c 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/string_interpolation.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/string_interpolation.dart
@@ -53,6 +53,7 @@
@Helper("a ${" b ${constBool}"} c")
/*member: stringInterpolation8:
resolved=StringLiteral('a ${StringLiteral(' b ${StaticGet(constBool)}')} c')
-evaluate=StringLiteral('a b ${StaticGet(constBool)} c')*/
+evaluate=StringLiteral('a b true c')
+constBool=BooleanLiteral(true)*/
void stringInterpolation8() {}
diff --git a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/unary.dart b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/unary.dart
index 096d24a..3d4483c 100644
--- a/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/unary.dart
+++ b/pkg/_fe_analyzer_shared/test/metadata/evaluate_data/unary.dart
@@ -37,11 +37,13 @@
@Helper(!constBool)
/*member: unary5:
resolved=UnaryExpression(!StaticGet(constBool))
-evaluate=UnaryExpression(!StaticGet(constBool))*/
+evaluate=BooleanLiteral(false)
+constBool=BooleanLiteral(true)*/
void unary5() {}
@Helper(-constInt)
/*member: unary6:
resolved=UnaryExpression(-StaticGet(constInt))
-evaluate=UnaryExpression(-StaticGet(constInt))*/
+evaluate=IntegerLiteral(value=-42)
+constInt=IntegerLiteral(42)*/
void unary6() {}
diff --git a/pkg/analyzer/lib/src/summary2/macro_metadata.dart b/pkg/analyzer/lib/src/summary2/macro_metadata.dart
index 6b0cd3b..346d9bb 100644
--- a/pkg/analyzer/lib/src/summary2/macro_metadata.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_metadata.dart
@@ -12,6 +12,19 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/scope.dart';
+/// Returns the [shared.Expression] for the constant initializer of [reference].
+shared.Expression? getFieldInitializer(shared.FieldReference reference) {
+ if (reference is _VariableReference) {
+ var element = reference._element;
+ if (element is VariableElementImpl) {
+ return parseFieldInitializer(element);
+ }
+ }
+ assert(false,
+ "Unexpected field reference $reference (${reference.runtimeType})");
+ return null;
+}
+
/// Creates a [shared.Expression] for the [annotation].
///
/// If [delayLookupForTesting] is `true`, identifiers are not looked up in their
@@ -25,6 +38,7 @@
var compilationUnit = annotation.compilationUnit;
var annotationImpl = annotation.annotationAst;
var uri = compilationUnit.source.uri;
+ // TODO(johnniwinther): Find the right scope for non-top-level annotations.
var scope = _Scope(compilationUnit);
var references = _References();
// The token stream might have been detached, so we ensure an EOF while
@@ -39,6 +53,43 @@
return expression;
}
+/// Creates a [shared.Expression] for the initializer of the constant
+/// [variable].
+///
+/// If [delayLookupForTesting] is `true`, identifiers are not looked up in their
+/// corresponding scopes. This means that the return expression will contain
+/// [shared.UnresolvedIdentifier] nodes, as if the identifier wasn't in scope.
+/// A subsequent call to [shared.Expression.resolve] will perform the lookup
+/// a create the resolved expression. This is used in testing to mimic the
+/// scenario in which the declaration is added to the scope via macros.
+shared.Expression? parseFieldInitializer(VariableElementImpl variable,
+ {bool delayLookupForTesting = false}) {
+ var initializer = variable.constantInitializer;
+ if (initializer == null) return null;
+ var enclosingElement = variable.enclosingElement3;
+ while (enclosingElement != null) {
+ if (enclosingElement is CompilationUnitElementImpl) {
+ var uri = enclosingElement.source.uri;
+ // TODO(johnniwinther): Find the right scope for class members.
+ var scope = _Scope(enclosingElement);
+ var references = _References();
+ // The token stream might have been detached, so we ensure an EOF while
+ // parsing the annotation.
+ var endTokenNext = initializer.endToken.next;
+ initializer.endToken.next ??= Token.eof(-1);
+ var expression = shared.parseExpression(
+ initializer.beginToken, uri, scope, references,
+ isDartLibrary:
+ uri.isScheme("dart") || uri.isScheme("org-dartlang-sdk"),
+ delayLookupForTesting: delayLookupForTesting);
+ initializer.endToken.next = endTokenNext;
+ return expression;
+ }
+ enclosingElement = enclosingElement.enclosingElement3;
+ }
+ return null;
+}
+
shared.Proto _elementToProto(Element element, String name) {
if (element is ClassElement) {
var reference = _ClassReference(element);
diff --git a/pkg/analyzer/test/id_tests/metadata_evaluate_test.dart b/pkg/analyzer/test/id_tests/metadata_evaluate_test.dart
index 6b8f4a5..404610be 100644
--- a/pkg/analyzer/test/id_tests/metadata_evaluate_test.dart
+++ b/pkg/analyzer/test/id_tests/metadata_evaluate_test.dart
@@ -61,7 +61,8 @@
for (ElementAnnotation annotation in element.metadata) {
if (annotation is ElementAnnotationImpl) {
var resolved = parseAnnotation(annotation);
- list.addAll(evaluationToText(resolved));
+ list.addAll(evaluationToText(resolved,
+ getFieldInitializer: getFieldInitializer));
}
}
if (list.isNotEmpty) {
diff --git a/pkg/front_end/lib/src/kernel/macro/metadata.dart b/pkg/front_end/lib/src/kernel/macro/metadata.dart
index fbf9ee7..c9a0ffd 100644
--- a/pkg/front_end/lib/src/kernel/macro/metadata.dart
+++ b/pkg/front_end/lib/src/kernel/macro/metadata.dart
@@ -24,6 +24,7 @@
import '../../builder/null_type_declaration_builder.dart';
import '../../builder/prefix_builder.dart';
import '../../builder/procedure_builder.dart';
+import '../../source/source_field_builder.dart';
// Coverage-ignore(suite): Not run.
final Uri dummyUri = Uri.parse('dummy:uri');
@@ -52,6 +53,39 @@
}
// Coverage-ignore(suite): Not run.
+/// Creates a [shared.Expression] for the initializer at [initializerToken].
+///
+/// If [delayLookupForTesting] is `true`, identifiers are not looked up in their
+/// corresponding scopes. This means that the return expression will contain
+/// [shared.UnresolvedIdentifier] nodes, as if the identifier wasn't in scope.
+/// A subsequent call to [shared.Expression.resolve] will perform the lookup
+/// a create the resolved expression. This is used in testing to mimic the
+/// scenario in which the declaration is added to the scope via macros.
+shared.Expression parseFieldInitializer(Loader loader, Token initializerToken,
+ Uri importUri, Uri fileUri, LookupScope scope,
+ {bool delayLookupForTesting = false}) {
+ return shared.parseExpression(initializerToken, fileUri,
+ new AnnotationScope(scope), new References(loader),
+ isDartLibrary: _isDartLibrary(importUri, fileUri),
+ delayLookupForTesting: delayLookupForTesting);
+}
+
+// Coverage-ignore(suite): Not run.
+/// Returns the [shared.Expression] for the constant initializer of [reference].
+shared.Expression? getFieldInitializer(shared.FieldReference reference) {
+ if (reference is FieldReference) {
+ FieldBuilder element = reference.builder;
+ if (element is SourceFieldBuilder) {
+ return element.initializerExpression;
+ }
+ } else {
+ assert(false,
+ "Unexpected field reference $reference (${reference.runtimeType})");
+ }
+ return null;
+}
+
+// Coverage-ignore(suite): Not run.
shared.Proto builderToProto(Builder builder, String name) {
if (builder is FieldBuilder) {
return new shared.FieldProto(new FieldReference(builder));
diff --git a/pkg/front_end/lib/src/source/source_field_builder.dart b/pkg/front_end/lib/src/source/source_field_builder.dart
index d910054..1356d95 100644
--- a/pkg/front_end/lib/src/source/source_field_builder.dart
+++ b/pkg/front_end/lib/src/source/source_field_builder.dart
@@ -5,6 +5,7 @@
library fasta.field_builder;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
+import 'package:_fe_analyzer_shared/src/metadata/expressions.dart' as shared;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
@@ -32,6 +33,7 @@
import '../kernel/internal_ast.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/late_lowering.dart' as late_lowering;
+import '../kernel/macro/metadata.dart';
import '../kernel/member_covariance.dart';
import '../kernel/type_algorithms.dart';
import '../source/name_scheme.dart';
@@ -63,6 +65,8 @@
Token? _constInitializerToken;
+ shared.Expression? _initializerExpression;
+
/// Whether the body of this field has been built.
///
/// Constant fields have their initializer built in the outline so we avoid
@@ -497,6 +501,7 @@
isClassMember &&
classBuilder!.declaresConstConstructor)) &&
_constInitializerToken != null) {
+ Token initializerToken = _constInitializerToken!;
LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope;
BodyBuilder bodyBuilder = libraryBuilder.loader
.createBodyBuilderForOutlineExpression(
@@ -505,15 +510,23 @@
isConst ? ConstantContext.inferred : ConstantContext.required;
Expression initializer = bodyBuilder.typeInferrer
.inferFieldInitializer(bodyBuilder, fieldType,
- bodyBuilder.parseFieldInitializer(_constInitializerToken!))
+ bodyBuilder.parseFieldInitializer(initializerToken))
.expression;
buildBody(classHierarchy.coreTypes, initializer);
bodyBuilder.performBacklogComputations();
+ if (computeSharedExpressionForTesting) {
+ // Coverage-ignore-block(suite): Not run.
+ _initializerExpression = parseFieldInitializer(libraryBuilder.loader,
+ initializerToken, libraryBuilder.importUri, fileUri, scope);
+ }
}
_constInitializerToken = null;
}
// Coverage-ignore(suite): Not run.
+ shared.Expression? get initializerExpression => _initializerExpression;
+
+ // Coverage-ignore(suite): Not run.
bool get hasOutlineExpressionsBuilt => _constInitializerToken == null;
DartType get fieldType => _fieldEncoding.type;
diff --git a/pkg/front_end/test/id_tests/metadata_evaluate_test.dart b/pkg/front_end/test/id_tests/metadata_evaluate_test.dart
index 13ae56b..f49d1d5 100644
--- a/pkg/front_end/test/id_tests/metadata_evaluate_test.dart
+++ b/pkg/front_end/test/id_tests/metadata_evaluate_test.dart
@@ -10,6 +10,7 @@
import 'package:_fe_analyzer_shared/src/metadata/ast.dart' as shared;
import 'package:front_end/src/base/common.dart';
import 'package:front_end/src/builder/member_builder.dart';
+import 'package:front_end/src/kernel/macro/metadata.dart';
import 'package:front_end/src/source/source_member_builder.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:front_end/src/testing/id_testing_utils.dart';
@@ -65,7 +66,8 @@
List<String> list = [];
for (MetadataBuilder metadataBuilder in metadata) {
shared.Expression resolved = metadataBuilder.expression!;
- list.addAll(evaluationToText(resolved));
+ list.addAll(evaluationToText(resolved,
+ getFieldInitializer: getFieldInitializer));
}
return '\n${list.join('\n')}';
}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 0ffef15..b991763 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -446,6 +446,8 @@
depfile
deprecating
deps
+dereference
+dereferences
dereferencing
deregister
descent