Add summary support for spread elements.
Change-Id: I5c306225aacca997ef104e7a2b18001dab38201d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96966
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 5d1c4d6..2cd3ae4 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -817,7 +817,7 @@
static ListLiteral listLiteral2(
Keyword keyword, TypeArgumentList typeArguments,
- [List<Expression> elements]) =>
+ [List<CollectionElement> elements]) =>
astFactory.listLiteral(
keyword == null ? null : TokenFactory.tokenFromKeyword(keyword),
typeArguments,
@@ -1126,6 +1126,12 @@
TypeAnnotation type, String parameterName) =>
simpleFormalParameter2(null, type, parameterName);
+ static SpreadElement spreadElement(
+ TokenType operator, Expression expression) =>
+ astFactory.spreadElement(
+ spreadOperator: TokenFactory.tokenFromType(operator),
+ expression: expression);
+
static StringInterpolation string([List<InterpolationElement> elements]) =>
astFactory.stringInterpolation(elements);
diff --git a/pkg/analyzer/lib/src/summary/expr_builder.dart b/pkg/analyzer/lib/src/summary/expr_builder.dart
index 8ef62ae..629798e 100644
--- a/pkg/analyzer/lib/src/summary/expr_builder.dart
+++ b/pkg/analyzer/lib/src/summary/expr_builder.dart
@@ -17,7 +17,7 @@
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
-bool _isSetOrMapEnabled(ExperimentStatus experimentStatus) =>
+bool _isSpreadOrControlFlowEnabled(ExperimentStatus experimentStatus) =>
experimentStatus.spread_collections ||
experimentStatus.control_flow_collections;
@@ -31,7 +31,7 @@
final ElementImpl context;
final UnlinkedExpr _uc;
final bool requireValidConst;
- final bool useSetOrMap;
+ final bool isSpreadOrControlFlowEnabled;
final bool becomeSetOrMap;
int intPtr = 0;
@@ -58,9 +58,10 @@
this.becomeSetOrMap: true,
}) : this.parametersInScope =
parametersInScope ?? _parametersInScope(context),
- this.useSetOrMap = _isSetOrMapEnabled((resynthesizer
- .library.context.analysisOptions as AnalysisOptionsImpl)
- .experimentStatus);
+ this.isSpreadOrControlFlowEnabled = _isSpreadOrControlFlowEnabled(
+ (resynthesizer.library.context.analysisOptions
+ as AnalysisOptionsImpl)
+ .experimentStatus);
bool get hasNonEmptyExpr => _uc != null && _uc.operations.isNotEmpty;
@@ -239,7 +240,7 @@
break;
case UnlinkedExprOperation.makeTypedSet:
TypeAnnotation itemType = _newTypeName();
- if (useSetOrMap) {
+ if (isSpreadOrControlFlowEnabled) {
_pushSetOrMap(
AstTestFactory.typeArgumentList(<TypeAnnotation>[itemType]));
} else {
@@ -316,6 +317,12 @@
case UnlinkedExprOperation.pushThis:
_push(AstTestFactory.thisExpression());
break;
+ case UnlinkedExprOperation.spreadElement:
+ _pushSpread(TokenType.PERIOD_PERIOD_PERIOD);
+ break;
+ case UnlinkedExprOperation.nullAwareSpreadElement:
+ _pushSpread(TokenType.PERIOD_PERIOD_PERIOD_QUESTION);
+ break;
case UnlinkedExprOperation.cascadeSectionBegin:
case UnlinkedExprOperation.cascadeSectionEnd:
case UnlinkedExprOperation.pushLocalFunctionReference:
@@ -618,7 +625,7 @@
CollectionElement _popCollectionElement() => stack.removeLast();
- void _push(Expression expr) {
+ void _push(CollectionElement expr) {
stack.add(expr);
}
@@ -755,9 +762,10 @@
void _pushList(TypeArgumentList typeArguments) {
int count = _uc.ints[intPtr++];
- List<Expression> elements = <Expression>[];
+ List<CollectionElement> elements =
+ isSpreadOrControlFlowEnabled ? <CollectionElement>[] : <Expression>[];
for (int i = 0; i < count; i++) {
- elements.insert(0, _pop());
+ elements.insert(0, _popCollectionElement());
}
var typeArg = typeArguments == null
? resynthesizer.typeProvider.dynamicType
@@ -830,7 +838,7 @@
: typeArguments.arguments[1].type;
var staticType =
resynthesizer.typeProvider.mapType.instantiate([keyType, valueType]);
- if (useSetOrMap) {
+ if (isSpreadOrControlFlowEnabled) {
_push(
AstTestFactory.setOrMapLiteral(Keyword.CONST, typeArguments, entries)
..staticType = staticType);
@@ -915,6 +923,11 @@
_push(setOrMapLiteral..staticType = staticType);
}
+ void _pushSpread(TokenType operator) {
+ Expression operand = _pop();
+ _push(AstTestFactory.spreadElement(operator, operand));
+ }
+
List<Expression> _removeTopExpressions(int count) {
int start = stack.length - count;
int end = stack.length;
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 29ee198..6745d48 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -972,7 +972,15 @@
/// Pop the top 2 values from the stack, place them in a [MapLiteralEntry],
/// and push the result back onto the stack.
- makeMapLiteralEntry
+ makeMapLiteralEntry,
+
+ /// Pop the top value from the stack, convert it to a spread element of type
+ /// `...`, and push the result back onto the stack.
+ spreadElement,
+
+ /// Pop the top value from the stack, convert it to a spread element of type
+ /// `...?`, and push the result back onto the stack.
+ nullAwareSpreadElement
}
/// Enum used to indicate the kind of a parameter.
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index c97cf91..f000abb 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -3868,6 +3868,14 @@
/// Pop the top 2 values from the stack, place them in a [MapLiteralEntry],
/// and push the result back onto the stack.
makeMapLiteralEntry,
+
+ /// Pop the top value from the stack, convert it to a spread element of type
+ /// `...`, and push the result back onto the stack.
+ spreadElement,
+
+ /// Pop the top value from the stack, convert it to a spread element of type
+ /// `...?`, and push the result back onto the stack.
+ nullAwareSpreadElement,
}
/// Unlinked summary information about an import declaration.
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
index 056a4bf..71af96b 100644
--- a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -541,6 +541,13 @@
_serialize(element.key);
_serialize(element.value);
operations.add(UnlinkedExprOperation.makeMapLiteralEntry);
+ } else if (element is SpreadElement) {
+ _serialize(element.expression);
+ bool isNullAware = element.spreadOperator.type ==
+ TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
+ operations.add(isNullAware
+ ? UnlinkedExprOperation.nullAwareSpreadElement
+ : UnlinkedExprOperation.spreadElement);
} else {
// TODO(paulberry): Implement serialization for spread and control flow
// elements.
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index b7a7b5c..6813ec5 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -276,7 +276,7 @@
if (e is ConstructorElementImpl) {
if (e.constantInitializers != null) {
- writeList(' : ', '', e.constantInitializers, ', ', writeExpression);
+ writeList(' : ', '', e.constantInitializers, ', ', writeNode);
}
}
@@ -307,209 +307,6 @@
buffer.writeln(';');
}
- void writeExpression(AstNode e, [Expression enclosing]) {
- bool needsParenthesis = e is Expression &&
- enclosing != null &&
- e.precedence2 < enclosing.precedence2;
-
- if (needsParenthesis) {
- buffer.write('(');
- }
-
- if (e == null) {
- buffer.write('<null>');
- } else if (e is SimpleIdentifier && e.name == '#invalidConst') {
- buffer.write('#invalidConst');
- } else if (e is AdjacentStrings) {
- writeList("'", "'", e.strings, '',
- (StringLiteral s) => buffer.write(s.stringValue),
- includeEmpty: true);
- } else if (e is Annotation) {
- buffer.write('@');
- writeExpression(e.name);
- if (e.constructorName != null) {
- buffer.write('.');
- writeExpression(e.constructorName);
- }
- if (e.arguments != null) {
- writeList('(', ')', e.arguments.arguments, ', ', writeExpression,
- includeEmpty: true);
- }
- } else if (e is AssertInitializer) {
- buffer.write('assert(');
- writeExpression(e.condition);
- if (e.message != null) {
- buffer.write(', ');
- writeExpression(e.message);
- }
- buffer.write(')');
- } else if (e is BinaryExpression) {
- writeExpression(e.leftOperand, e);
- buffer.write(' ');
- buffer.write(e.operator.lexeme);
- buffer.write(' ');
- writeExpression(e.rightOperand, e);
- } else if (e is BooleanLiteral) {
- buffer.write(e.value);
- } else if (e is ConditionalExpression) {
- writeExpression(e.condition);
- buffer.write(' ? ');
- writeExpression(e.thenExpression);
- buffer.write(' : ');
- writeExpression(e.elseExpression);
- } else if (e is ConstructorFieldInitializer) {
- writeExpression(e.fieldName);
- buffer.write(' = ');
- writeExpression(e.expression);
- } else if (e is ConstructorName) {
- writeExpression(e.type);
- if (e.name != null) {
- buffer.write('.');
- writeExpression(e.name);
- }
- } else if (e is DoubleLiteral) {
- buffer.write(e.value);
- } else if (e is InstanceCreationExpression) {
- if (e.keyword != null) {
- buffer.write(e.keyword.lexeme);
- buffer.write(' ');
- }
- writeExpression(e.constructorName);
- writeList('(', ')', e.argumentList.arguments, ', ', writeExpression,
- includeEmpty: true);
- } else if (e is IntegerLiteral) {
- buffer.write(e.value);
- } else if (e is InterpolationExpression) {
- buffer.write(r'${');
- writeExpression(e.expression);
- buffer.write(r'}');
- } else if (e is InterpolationString) {
- buffer.write(e.value.replaceAll("'", r"\'"));
- } else if (e is ListLiteral) {
- if (e.constKeyword != null) {
- buffer.write('const ');
- }
- if (e.typeArguments != null) {
- writeList('<', '>', e.typeArguments.arguments, ', ', writeExpression);
- } else if (withTypes) {
- writeInterfaceTypeArgsComment(e);
- }
- writeList('[', ']', e.elements2, ', ', writeExpression,
- includeEmpty: true);
- } else if (e is Label) {
- writeExpression(e.label);
- buffer.write(': ');
- } else if (e is SetOrMapLiteral) {
- if (e.constKeyword != null) {
- buffer.write('const ');
- }
- if (e.typeArguments != null) {
- writeList('<', '>', e.typeArguments.arguments, ', ', writeExpression);
- } else if (withTypes) {
- writeInterfaceTypeArgsComment(e);
- }
- writeList('{', '}', e.elements2, ', ', writeExpression,
- includeEmpty: true);
- if (e.isMap) {
- buffer.write('/*isMap*/');
- }
- if (e.isSet) {
- buffer.write('/*isSet*/');
- }
- } else if (e is MapLiteralEntry) {
- writeExpression(e.key);
- buffer.write(': ');
- writeExpression(e.value);
- } else if (e is MethodInvocation) {
- if (e.target != null) {
- writeExpression(e.target);
- buffer.write(e.operator);
- }
- writeExpression(e.methodName);
- if (e.typeArguments != null) {
- writeList('<', '>', e.typeArguments.arguments, ', ', writeExpression);
- }
- writeList('(', ')', e.argumentList.arguments, ', ', writeExpression,
- includeEmpty: true);
- } else if (e is NamedExpression) {
- writeExpression(e.name);
- buffer.write(e.expression);
- } else if (e is NullLiteral) {
- buffer.write('null');
- } else if (e is ParenthesizedExpression) {
- writeExpression(e.expression, e);
- } else if (e is PrefixExpression) {
- buffer.write(e.operator.lexeme);
- writeExpression(e.operand, e);
- } else if (e is PrefixedIdentifier) {
- writeExpression(e.prefix);
- buffer.write('.');
- writeExpression(e.identifier);
- } else if (e is PropertyAccess) {
- writeExpression(e.target, e);
- buffer.write('.');
- writeExpression(e.propertyName);
- } else if (e is RedirectingConstructorInvocation) {
- buffer.write('this');
- if (e.constructorName != null) {
- buffer.write('.');
- writeExpression(e.constructorName);
- }
- writeList('(', ')', e.argumentList.arguments, ', ', writeExpression,
- includeEmpty: true);
- } else if (e is SimpleIdentifier) {
- if (withConstElements) {
- buffer.writeln();
- buffer.write(' ' * 4);
- buffer.write(e.name);
- buffer.write('/*');
- buffer.write('location: ');
- buffer.write(_getElementLocationString(e.staticElement));
- buffer.write('*/');
- } else {
- buffer.write(e.name);
- }
- } else if (e is SimpleStringLiteral) {
- buffer.write("'");
- buffer.write(e.value.replaceAll("'", r"\'"));
- buffer.write("'");
- } else if (e is StringInterpolation) {
- buffer.write("'");
- e.elements.forEach(writeExpression);
- buffer.write("'");
- } else if (e is SuperConstructorInvocation) {
- buffer.write('super');
- if (e.constructorName != null) {
- buffer.write('.');
- writeExpression(e.constructorName);
- }
- writeList('(', ')', e.argumentList.arguments, ', ', writeExpression,
- includeEmpty: true);
- } else if (e is SuperExpression) {
- buffer.write('super');
- } else if (e is SymbolLiteral) {
- buffer.write('#');
- writeList('', '', e.components, '.',
- (Token token) => buffer.write(token.lexeme));
- } else if (e is ThisExpression) {
- buffer.write('this');
- } else if (e is ThrowExpression) {
- buffer.write('throw ');
- writeExpression(e.expression);
- } else if (e is TypeName) {
- writeExpression(e.name);
- if (e.typeArguments != null) {
- writeList('<', '>', e.typeArguments.arguments, ', ', writeExpression);
- }
- } else {
- fail('Unsupported expression type: ${e.runtimeType}');
- }
-
- if (needsParenthesis) {
- buffer.write(')');
- }
- }
-
void writeFunctionElement(FunctionElement e) {
writeDocumentation(e);
writeMetadata(e, '', '\n');
@@ -631,7 +428,7 @@
void writeMetadata(Element e, String prefix, String separator) {
if (e.metadata.isNotEmpty) {
writeList(prefix, '', e.metadata, '$separator$prefix', (a) {
- writeExpression((a as ElementAnnotationImpl).annotationAst);
+ writeNode((a as ElementAnnotationImpl).annotationAst);
});
buffer.write(separator);
}
@@ -681,6 +478,210 @@
}
}
+ void writeNode(AstNode e, [Expression enclosing]) {
+ bool needsParenthesis = e is Expression &&
+ enclosing != null &&
+ e.precedence2 < enclosing.precedence2;
+
+ if (needsParenthesis) {
+ buffer.write('(');
+ }
+
+ if (e == null) {
+ buffer.write('<null>');
+ } else if (e is SimpleIdentifier && e.name == '#invalidConst') {
+ buffer.write('#invalidConst');
+ } else if (e is AdjacentStrings) {
+ writeList("'", "'", e.strings, '',
+ (StringLiteral s) => buffer.write(s.stringValue),
+ includeEmpty: true);
+ } else if (e is Annotation) {
+ buffer.write('@');
+ writeNode(e.name);
+ if (e.constructorName != null) {
+ buffer.write('.');
+ writeNode(e.constructorName);
+ }
+ if (e.arguments != null) {
+ writeList('(', ')', e.arguments.arguments, ', ', writeNode,
+ includeEmpty: true);
+ }
+ } else if (e is AssertInitializer) {
+ buffer.write('assert(');
+ writeNode(e.condition);
+ if (e.message != null) {
+ buffer.write(', ');
+ writeNode(e.message);
+ }
+ buffer.write(')');
+ } else if (e is BinaryExpression) {
+ writeNode(e.leftOperand, e);
+ buffer.write(' ');
+ buffer.write(e.operator.lexeme);
+ buffer.write(' ');
+ writeNode(e.rightOperand, e);
+ } else if (e is BooleanLiteral) {
+ buffer.write(e.value);
+ } else if (e is ConditionalExpression) {
+ writeNode(e.condition);
+ buffer.write(' ? ');
+ writeNode(e.thenExpression);
+ buffer.write(' : ');
+ writeNode(e.elseExpression);
+ } else if (e is ConstructorFieldInitializer) {
+ writeNode(e.fieldName);
+ buffer.write(' = ');
+ writeNode(e.expression);
+ } else if (e is ConstructorName) {
+ writeNode(e.type);
+ if (e.name != null) {
+ buffer.write('.');
+ writeNode(e.name);
+ }
+ } else if (e is DoubleLiteral) {
+ buffer.write(e.value);
+ } else if (e is InstanceCreationExpression) {
+ if (e.keyword != null) {
+ buffer.write(e.keyword.lexeme);
+ buffer.write(' ');
+ }
+ writeNode(e.constructorName);
+ writeList('(', ')', e.argumentList.arguments, ', ', writeNode,
+ includeEmpty: true);
+ } else if (e is IntegerLiteral) {
+ buffer.write(e.value);
+ } else if (e is InterpolationExpression) {
+ buffer.write(r'${');
+ writeNode(e.expression);
+ buffer.write(r'}');
+ } else if (e is InterpolationString) {
+ buffer.write(e.value.replaceAll("'", r"\'"));
+ } else if (e is ListLiteral) {
+ if (e.constKeyword != null) {
+ buffer.write('const ');
+ }
+ if (e.typeArguments != null) {
+ writeList('<', '>', e.typeArguments.arguments, ', ', writeNode);
+ } else if (withTypes) {
+ writeInterfaceTypeArgsComment(e);
+ }
+ writeList('[', ']', e.elements2, ', ', writeNode, includeEmpty: true);
+ } else if (e is Label) {
+ writeNode(e.label);
+ buffer.write(': ');
+ } else if (e is SetOrMapLiteral) {
+ if (e.constKeyword != null) {
+ buffer.write('const ');
+ }
+ if (e.typeArguments != null) {
+ writeList('<', '>', e.typeArguments.arguments, ', ', writeNode);
+ } else if (withTypes) {
+ writeInterfaceTypeArgsComment(e);
+ }
+ writeList('{', '}', e.elements2, ', ', writeNode, includeEmpty: true);
+ if (e.isMap) {
+ buffer.write('/*isMap*/');
+ }
+ if (e.isSet) {
+ buffer.write('/*isSet*/');
+ }
+ } else if (e is MapLiteralEntry) {
+ writeNode(e.key);
+ buffer.write(': ');
+ writeNode(e.value);
+ } else if (e is MethodInvocation) {
+ if (e.target != null) {
+ writeNode(e.target);
+ buffer.write(e.operator);
+ }
+ writeNode(e.methodName);
+ if (e.typeArguments != null) {
+ writeList('<', '>', e.typeArguments.arguments, ', ', writeNode);
+ }
+ writeList('(', ')', e.argumentList.arguments, ', ', writeNode,
+ includeEmpty: true);
+ } else if (e is NamedExpression) {
+ writeNode(e.name);
+ buffer.write(e.expression);
+ } else if (e is NullLiteral) {
+ buffer.write('null');
+ } else if (e is ParenthesizedExpression) {
+ writeNode(e.expression, e);
+ } else if (e is PrefixExpression) {
+ buffer.write(e.operator.lexeme);
+ writeNode(e.operand, e);
+ } else if (e is PrefixedIdentifier) {
+ writeNode(e.prefix);
+ buffer.write('.');
+ writeNode(e.identifier);
+ } else if (e is PropertyAccess) {
+ writeNode(e.target, e);
+ buffer.write('.');
+ writeNode(e.propertyName);
+ } else if (e is RedirectingConstructorInvocation) {
+ buffer.write('this');
+ if (e.constructorName != null) {
+ buffer.write('.');
+ writeNode(e.constructorName);
+ }
+ writeList('(', ')', e.argumentList.arguments, ', ', writeNode,
+ includeEmpty: true);
+ } else if (e is SimpleIdentifier) {
+ if (withConstElements) {
+ buffer.writeln();
+ buffer.write(' ' * 4);
+ buffer.write(e.name);
+ buffer.write('/*');
+ buffer.write('location: ');
+ buffer.write(_getElementLocationString(e.staticElement));
+ buffer.write('*/');
+ } else {
+ buffer.write(e.name);
+ }
+ } else if (e is SimpleStringLiteral) {
+ buffer.write("'");
+ buffer.write(e.value.replaceAll("'", r"\'"));
+ buffer.write("'");
+ } else if (e is StringInterpolation) {
+ buffer.write("'");
+ e.elements.forEach(writeNode);
+ buffer.write("'");
+ } else if (e is SuperConstructorInvocation) {
+ buffer.write('super');
+ if (e.constructorName != null) {
+ buffer.write('.');
+ writeNode(e.constructorName);
+ }
+ writeList('(', ')', e.argumentList.arguments, ', ', writeNode,
+ includeEmpty: true);
+ } else if (e is SuperExpression) {
+ buffer.write('super');
+ } else if (e is SymbolLiteral) {
+ buffer.write('#');
+ writeList('', '', e.components, '.',
+ (Token token) => buffer.write(token.lexeme));
+ } else if (e is ThisExpression) {
+ buffer.write('this');
+ } else if (e is ThrowExpression) {
+ buffer.write('throw ');
+ writeNode(e.expression);
+ } else if (e is TypeName) {
+ writeNode(e.name);
+ if (e.typeArguments != null) {
+ writeList('<', '>', e.typeArguments.arguments, ', ', writeNode);
+ }
+ } else if (e is SpreadElement) {
+ buffer.write(e.spreadOperator.lexeme);
+ writeNode(e.expression);
+ } else {
+ fail('Unsupported expression type: ${e.runtimeType}');
+ }
+
+ if (needsParenthesis) {
+ buffer.write(')');
+ }
+ }
+
void writeParameterElement(ParameterElement e) {
String defaultValueSeparator;
Expression defaultValue;
@@ -729,7 +730,7 @@
if (defaultValue != null) {
buffer.write(defaultValueSeparator);
- writeExpression(defaultValue);
+ writeNode(defaultValue);
}
buffer.write(closeString);
@@ -867,7 +868,7 @@
Expression initializer = (e as ConstVariableElement).constantInitializer;
if (initializer != null) {
buffer.write(' = ');
- writeExpression(initializer);
+ writeNode(initializer);
}
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 139ad19..d90e62a 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -9,8 +9,8 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
@@ -30,7 +30,6 @@
*/
abstract class AbstractResynthesizeTest with ResourceProviderMixin {
DeclaredVariables declaredVariables = new DeclaredVariables();
- AnalysisOptionsImpl analysisOptions = AnalysisOptionsImpl();
SourceFactory sourceFactory;
MockSdk sdk;
@@ -2579,6 +2578,52 @@
}
}
+ test_const_list_spread() async {
+ experimentStatus = ExperimentStatus(spread_collections: true);
+ var library = await checkLibrary('''
+const Object x = const <int>[...<int>[1]];
+''');
+ if (isAstBasedSummary) {
+ checkElementText(
+ library,
+ '''
+const Object x = const <
+ int/*location: dart:core;int*/>[...<
+ int/*location: dart:core;int*/>[1]];
+''',
+ withTypes: true);
+ } else {
+ checkElementText(library, '''
+const Object x = const <
+ int/*location: dart:core;int*/>[...const <
+ int/*location: dart:core;int*/>[1]];
+''');
+ }
+ }
+
+ test_const_list_spread_null_aware() async {
+ experimentStatus = ExperimentStatus(spread_collections: true);
+ var library = await checkLibrary('''
+const Object x = const <int>[...?<int>[1]];
+''');
+ if (isAstBasedSummary) {
+ checkElementText(
+ library,
+ '''
+const Object x = const <
+ int/*location: dart:core;int*/>[...?<
+ int/*location: dart:core;int*/>[1]];
+''',
+ withTypes: true);
+ } else {
+ checkElementText(library, '''
+const Object x = const <
+ int/*location: dart:core;int*/>[...?const <
+ int/*location: dart:core;int*/>[1]];
+''');
+ }
+ }
+
test_const_map_inferredType() async {
// The summary needs to contain enough information so that when the constant
// is resynthesized, the constant value can get the type that was computed
@@ -2602,6 +2647,60 @@
}
}
+ test_const_map_spread() async {
+ experimentStatus = ExperimentStatus(spread_collections: true);
+ var library = await checkLibrary('''
+const Object x = const <int, int>{...<int, int>{1: 2}};
+''');
+ if (isAstBasedSummary) {
+ checkElementText(
+ library,
+ '''
+const Object x = const <
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{...<
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{1: 2}/*isMap*/}/*isMap*/;
+''',
+ withTypes: true);
+ } else {
+ checkElementText(library, '''
+const Object x = const <
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{...const <
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{1: 2}/*isMap*/}/*isMap*/;
+''');
+ }
+ }
+
+ test_const_map_spread_null_aware() async {
+ experimentStatus = ExperimentStatus(spread_collections: true);
+ var library = await checkLibrary('''
+const Object x = const <int, int>{...?<int, int>{1: 2}};
+''');
+ if (isAstBasedSummary) {
+ checkElementText(
+ library,
+ '''
+const Object x = const <
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{...?<
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{1: 2}/*isMap*/}/*isMap*/;
+''',
+ withTypes: true);
+ } else {
+ checkElementText(library, '''
+const Object x = const <
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{...?const <
+ int/*location: dart:core;int*/,
+ int/*location: dart:core;int*/>{1: 2}/*isMap*/}/*isMap*/;
+''');
+ }
+ }
+
test_const_parameterDefaultValue_initializingFormal_functionTyped() async {
var library = await checkLibrary(r'''
class C {
@@ -3064,6 +3163,52 @@
}
}
+ test_const_set_spread() async {
+ experimentStatus = ExperimentStatus(spread_collections: true);
+ var library = await checkLibrary('''
+const Object x = const <int>{...<int>{1}};
+''');
+ if (isAstBasedSummary) {
+ checkElementText(
+ library,
+ '''
+const Object x = const <
+ int/*location: dart:core;int*/>{...<
+ int/*location: dart:core;int*/>{1}/*isSet*/}/*isSet*/;
+''',
+ withTypes: true);
+ } else {
+ checkElementText(library, '''
+const Object x = const <
+ int/*location: dart:core;int*/>{...const <
+ int/*location: dart:core;int*/>{1}/*isSet*/}/*isSet*/;
+''');
+ }
+ }
+
+ test_const_set_spread_null_aware() async {
+ experimentStatus = ExperimentStatus(spread_collections: true);
+ var library = await checkLibrary('''
+const Object x = const <int>{...?<int>{1}};
+''');
+ if (isAstBasedSummary) {
+ checkElementText(
+ library,
+ '''
+const Object x = const <
+ int/*location: dart:core;int*/>{...?<
+ int/*location: dart:core;int*/>{1}/*isSet*/}/*isSet*/;
+''',
+ withTypes: true);
+ } else {
+ checkElementText(library, '''
+const Object x = const <
+ int/*location: dart:core;int*/>{...?const <
+ int/*location: dart:core;int*/>{1}/*isSet*/}/*isSet*/;
+''');
+ }
+ }
+
test_const_topLevel_binary() async {
var library = await checkLibrary(r'''
const vEqual = 1 == 2;
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index b45006a..c69533d 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -2754,6 +2754,34 @@
]);
}
+ test_constExpr_list_spread() {
+ experimentStatus = ExperimentStatus(
+ control_flow_collections: true, spread_collections: true);
+ UnlinkedVariable variable = serializeVariableText('const v = [...[]];');
+ assertUnlinkedConst(variable.initializer.bodyExpr, '[...[]]', operators: [
+ UnlinkedExprOperation.makeUntypedList,
+ UnlinkedExprOperation.spreadElement,
+ UnlinkedExprOperation.makeUntypedList
+ ], ints: [
+ 0,
+ 1
+ ]);
+ }
+
+ test_constExpr_list_spread_null_aware() {
+ experimentStatus = ExperimentStatus(
+ control_flow_collections: true, spread_collections: true);
+ UnlinkedVariable variable = serializeVariableText('const v = [...?[]];');
+ assertUnlinkedConst(variable.initializer.bodyExpr, '[...?[]]', operators: [
+ UnlinkedExprOperation.makeUntypedList,
+ UnlinkedExprOperation.nullAwareSpreadElement,
+ UnlinkedExprOperation.makeUntypedList
+ ], ints: [
+ 0,
+ 1
+ ]);
+ }
+
test_constExpr_makeSymbol() {
UnlinkedVariable variable = serializeVariableText('const v = #a.bb.ccc;');
assertUnlinkedConst(variable.initializer.bodyExpr, '#a.bb.ccc',
@@ -3123,6 +3151,62 @@
);
}
+ test_constExpr_map_spread() {
+ experimentStatus = ExperimentStatus(
+ control_flow_collections: true, spread_collections: true);
+ UnlinkedVariable variable =
+ serializeVariableText('const v = <int, String>{...<int, String>{}};');
+ assertUnlinkedConst(
+ variable.initializer.bodyExpr, '<int, String>{...<int, String>{}}',
+ operators: [
+ UnlinkedExprOperation.makeTypedMap2,
+ UnlinkedExprOperation.spreadElement,
+ UnlinkedExprOperation.makeTypedMap2
+ ],
+ ints: [
+ 0,
+ 1
+ ],
+ referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_map_spread_null_aware() {
+ experimentStatus = ExperimentStatus(
+ control_flow_collections: true, spread_collections: true);
+ UnlinkedVariable variable =
+ serializeVariableText('const v = <int, String>{...?<int, String>{}};');
+ assertUnlinkedConst(
+ variable.initializer.bodyExpr, '<int, String>{...?<int, String>{}}',
+ operators: [
+ UnlinkedExprOperation.makeTypedMap2,
+ UnlinkedExprOperation.nullAwareSpreadElement,
+ UnlinkedExprOperation.makeTypedMap2
+ ],
+ ints: [
+ 0,
+ 1
+ ],
+ referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'String',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
test_constExpr_parenthesized() {
UnlinkedVariable variable = serializeVariableText('const v = (1 + 2) * 3;');
assertUnlinkedConst(variable.initializer.bodyExpr, '(1 + 2) * 3',
@@ -3841,6 +3925,52 @@
operators: [UnlinkedExprOperation.pushTrue]);
}
+ test_constExpr_set_spread() {
+ experimentStatus = ExperimentStatus(
+ control_flow_collections: true, spread_collections: true);
+ UnlinkedVariable variable =
+ serializeVariableText('const v = <int>{...<int>{}};');
+ assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{...<int>{}}',
+ operators: [
+ UnlinkedExprOperation.makeTypedSet,
+ UnlinkedExprOperation.spreadElement,
+ UnlinkedExprOperation.makeTypedSet
+ ],
+ ints: [
+ 0,
+ 1
+ ],
+ referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
+ test_constExpr_set_spread_null_aware() {
+ experimentStatus = ExperimentStatus(
+ control_flow_collections: true, spread_collections: true);
+ UnlinkedVariable variable =
+ serializeVariableText('const v = <int>{...?<int>{}};');
+ assertUnlinkedConst(variable.initializer.bodyExpr, '<int>{...?<int>{}}',
+ operators: [
+ UnlinkedExprOperation.makeTypedSet,
+ UnlinkedExprOperation.nullAwareSpreadElement,
+ UnlinkedExprOperation.makeTypedSet
+ ],
+ ints: [
+ 0,
+ 1
+ ],
+ referenceValidators: [
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum),
+ (EntityRef r) => checkTypeRef(r, 'dart:core', 'int',
+ expectedKind: ReferenceKind.classOrEnum)
+ ]);
+ }
+
test_constructor() {
String text = 'class C { C(); }';
UnlinkedExecutable executable =
diff --git a/pkg/analyzer/test/src/summary/test_strategies.dart b/pkg/analyzer/test/src/summary/test_strategies.dart
index bfbe9fe..eed8b58 100644
--- a/pkg/analyzer/test/src/summary/test_strategies.dart
+++ b/pkg/analyzer/test/src/summary/test_strategies.dart
@@ -43,9 +43,11 @@
Scanner scanner =
new Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER);
Token token = scanner.tokenize();
- Parser parser =
- new Parser(NonExistingSource.unknown, AnalysisErrorListener.NULL_LISTENER)
- ..enableNonNullable = experimentStatus.non_nullable;
+ Parser parser = new Parser(
+ NonExistingSource.unknown, AnalysisErrorListener.NULL_LISTENER)
+ ..enableNonNullable = experimentStatus.non_nullable
+ ..enableSpreadCollections = experimentStatus.spread_collections
+ ..enableControlFlowCollections = experimentStatus.control_flow_collections;
CompilationUnit unit = parser.parseCompilationUnit(token);
unit.lineInfo = new LineInfo(scanner.lineStarts);
return unit;
@@ -175,6 +177,9 @@
.map((Source source) => source.uri.toString())
.toSet();
+ var analysisOptions = AnalysisOptionsImpl()
+ ..enabledExperiments = experimentStatus.toStringList();
+
Map<String, LinkedLibrary> linkedSummaries = link(nonSdkLibraryUris,
getDependency, getUnit, declaredVariables, analysisOptions);
@@ -222,7 +227,8 @@
contents = '';
}
- CompilationUnit unit = parseText(contents);
+ CompilationUnit unit =
+ parseText(contents, experimentStatus: experimentStatus);
UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
bundleAssembler.addUnlinkedUnit(source, unlinkedUnit);