Version 2.19.0-281.0.dev
Merge c515938ee4fe6ef19d9ad5deb060f8fae6ba02fb into dev
diff --git a/DEPS b/DEPS
index cc97cb7..652f108 100644
--- a/DEPS
+++ b/DEPS
@@ -95,7 +95,7 @@
"cli_util_rev": "b0adbba89442b2ea6fef39c7a82fe79cb31e1168",
"clock_rev": "97026d1657566bb0c9f5a33642712ec350e45084",
"collection_rev": "414ffa1bc8ba18bd608bbf916d95715311d89ac1",
- "convert_rev": "7145da14f9cd730e80fb4c6a10108fcfd205e8e7",
+ "convert_rev": "11d191e4cc517595f53f86dd193a7c01a7601228",
"crypto_rev": "7cf89d35b3d90786d9f7f75211b3b3cd7e4d173f",
"csslib_rev": "ba2eb2d80530eedefadaade338a09c2dd60410f3",
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart
index 3e8a7fd..cd44b25 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart
@@ -18,9 +18,18 @@
class AddKeyToConstructors extends CorrectionProducer {
@override
+ bool get canBeAppliedInBulk => true;
+
+ @override
+ bool get canBeAppliedToFile => true;
+
+ @override
FixKind get fixKind => DartFixKind.ADD_KEY_TO_CONSTRUCTORS;
@override
+ FixKind get multiFixKind => DartFixKind.ADD_KEY_TO_CONSTRUCTORS_MULTI;
+
+ @override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
var parent = node.parent;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index f7bbe36..b23b005 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -153,6 +153,11 @@
DartFixKindPriority.DEFAULT,
"Add 'key' to constructors",
);
+ static const ADD_KEY_TO_CONSTRUCTORS_MULTI = FixKind(
+ 'dart.fix.add.keyToConstructors.multi',
+ DartFixKindPriority.DEFAULT,
+ "Add 'key' to constructors everywhere in file",
+ );
static const ADD_LATE = FixKind(
'dart.fix.add.late',
DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart
index becec30..b549246 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart
@@ -5,12 +5,15 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test/expect.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
+ defineReflectiveTests(AddKeyToConstructorsBulkTest);
+ defineReflectiveTests(AddKeyToConstructorsInFileTest);
defineReflectiveTests(AddKeyToConstructorsTest);
defineReflectiveTests(
AddKeyToConstructorsWithoutNamedArgumentsAnywhereTest);
@@ -19,6 +22,77 @@
}
@reflectiveTest
+class AddKeyToConstructorsBulkTest extends BulkFixProcessorTest {
+ @override
+ String get lintCode => LintNames.use_key_in_widget_constructors;
+
+ @override
+ void setUp() {
+ super.setUp();
+ writeTestPackageConfig(
+ flutter: true,
+ );
+ }
+
+ Future<void> test_singleFile() async {
+ await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget1 extends StatelessWidget {
+}
+
+class MyWidget2 extends StatelessWidget {
+}
+''');
+ await assertHasFix(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget1 extends StatelessWidget {
+ const MyWidget1({super.key});
+}
+
+class MyWidget2 extends StatelessWidget {
+ const MyWidget2({super.key});
+}
+''');
+ }
+}
+
+@reflectiveTest
+class AddKeyToConstructorsInFileTest extends FixInFileProcessorTest {
+ @override
+ void setUp() {
+ super.setUp();
+ writeTestPackageConfig(
+ flutter: true,
+ );
+ }
+
+ Future<void> test_file() async {
+ createAnalysisOptionsFile(
+ lints: [LintNames.use_key_in_widget_constructors]);
+ await resolveTestCode(r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+ const MyWidget();
+ const MyWidget.named();
+}
+''');
+ var fixes = await getFixesForFirstError();
+ expect(fixes, hasLength(1));
+ assertProduces(fixes.first, r'''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+ const MyWidget({super.key});
+ const MyWidget.named({super.key});
+}
+''');
+ }
+}
+
+@reflectiveTest
class AddKeyToConstructorsTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.ADD_KEY_TO_CONSTRUCTORS;
diff --git a/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart b/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
index b33788c..471a629 100644
--- a/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
+++ b/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
@@ -93,16 +93,16 @@
);
} else if (expression is PropertyAccessImpl) {
var expressionTarget = expression.realTarget;
- return astFactory.propertyAccess(
- insertCascadeTargetIntoExpression(
+ return PropertyAccessImpl(
+ target: insertCascadeTargetIntoExpression(
expression: expressionTarget,
cascadeTarget: cascadeTarget,
),
// If we've reached the end, replace the `..` operator with `.`
- expressionTarget == cascadeTarget
+ operator: expressionTarget == cascadeTarget
? _synthesizeToken(TokenType.PERIOD, expression.operator)
: expression.operator,
- expression.propertyName,
+ propertyName: expression.propertyName,
);
}
throw UnimplementedError('Unhandled ${expression.runtimeType}'
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 710e64c..6c3f075 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -9937,7 +9937,10 @@
MethodElement? staticElement;
/// Initialize a newly created postfix expression.
- PostfixExpressionImpl(this._operand, this.operator) {
+ PostfixExpressionImpl({
+ required ExpressionImpl operand,
+ required this.operator,
+ }) : _operand = operand {
_becomeParentOf(_operand);
}
@@ -10067,7 +10070,12 @@
SimpleIdentifierImpl _identifier;
/// Initialize a newly created prefixed identifier.
- PrefixedIdentifierImpl(this._prefix, this.period, this._identifier) {
+ PrefixedIdentifierImpl({
+ required SimpleIdentifierImpl prefix,
+ required this.period,
+ required SimpleIdentifierImpl identifier,
+ }) : _prefix = prefix,
+ _identifier = identifier {
_becomeParentOf(_prefix);
_becomeParentOf(_identifier);
}
@@ -10158,7 +10166,10 @@
MethodElement? staticElement;
/// Initialize a newly created prefix expression.
- PrefixExpressionImpl(this.operator, this._operand) {
+ PrefixExpressionImpl({
+ required this.operator,
+ required ExpressionImpl operand,
+ }) : _operand = operand {
_becomeParentOf(_operand);
}
@@ -10241,7 +10252,12 @@
SimpleIdentifierImpl _propertyName;
/// Initialize a newly created property access expression.
- PropertyAccessImpl(this._target, this.operator, this._propertyName) {
+ PropertyAccessImpl({
+ required ExpressionImpl? target,
+ required this.operator,
+ required SimpleIdentifierImpl propertyName,
+ }) : _target = target,
+ _propertyName = propertyName {
_becomeParentOf(_target);
_becomeParentOf(_propertyName);
}
@@ -10729,8 +10745,13 @@
/// constructor with the given name with the given arguments. The
/// [constructorName] can be `null` if the constructor being invoked is the
/// unnamed constructor.
- RedirectingConstructorInvocationImpl(this.thisKeyword, this.period,
- this._constructorName, this._argumentList) {
+ RedirectingConstructorInvocationImpl({
+ required this.thisKeyword,
+ required this.period,
+ required SimpleIdentifierImpl? constructorName,
+ required ArgumentListImpl argumentList,
+ }) : _constructorName = constructorName,
+ _argumentList = argumentList {
_becomeParentOf(_constructorName);
_becomeParentOf(_argumentList);
}
@@ -10834,7 +10855,9 @@
Token rethrowKeyword;
/// Initialize a newly created rethrow expression.
- RethrowExpressionImpl(this.rethrowKeyword);
+ RethrowExpressionImpl({
+ required this.rethrowKeyword,
+ });
@override
Token get beginToken => rethrowKeyword;
@@ -10882,7 +10905,11 @@
/// Initialize a newly created return statement. The [expression] can be
/// `null` if no explicit value was provided.
- ReturnStatementImpl(this.returnKeyword, this._expression, this.semicolon) {
+ ReturnStatementImpl({
+ required this.returnKeyword,
+ required ExpressionImpl? expression,
+ required this.semicolon,
+ }) : _expression = expression {
_becomeParentOf(_expression);
}
@@ -10925,7 +10952,9 @@
Token scriptTag;
/// Initialize a newly created script tag.
- ScriptTagImpl(this.scriptTag);
+ ScriptTagImpl({
+ required this.scriptTag,
+ });
@override
Token get beginToken => scriptTag;
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 675ac91..215d967 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -130,43 +130,6 @@
ParenthesizedExpressionImpl(
leftParenthesis, expression as ExpressionImpl, rightParenthesis);
- PostfixExpressionImpl postfixExpression(Expression operand, Token operator) =>
- PostfixExpressionImpl(operand as ExpressionImpl, operator);
-
- PrefixedIdentifierImpl prefixedIdentifier(
- SimpleIdentifier prefix, Token period, SimpleIdentifier identifier) =>
- PrefixedIdentifierImpl(prefix as SimpleIdentifierImpl, period,
- identifier as SimpleIdentifierImpl);
-
- PrefixExpressionImpl prefixExpression(Token operator, Expression operand) =>
- PrefixExpressionImpl(operator, operand as ExpressionImpl);
-
- PropertyAccessImpl propertyAccess(
- Expression? target, Token operator, SimpleIdentifier propertyName) =>
- PropertyAccessImpl(target as ExpressionImpl?, operator,
- propertyName as SimpleIdentifierImpl);
-
- RedirectingConstructorInvocationImpl redirectingConstructorInvocation(
- Token thisKeyword,
- Token? period,
- SimpleIdentifier? constructorName,
- ArgumentList argumentList) =>
- RedirectingConstructorInvocationImpl(
- thisKeyword,
- period,
- constructorName as SimpleIdentifierImpl?,
- argumentList as ArgumentListImpl);
-
- RethrowExpressionImpl rethrowExpression(Token rethrowKeyword) =>
- RethrowExpressionImpl(rethrowKeyword);
-
- ReturnStatementImpl returnStatement(
- Token returnKeyword, Expression? expression, Token semicolon) =>
- ReturnStatementImpl(
- returnKeyword, expression as ExpressionImpl?, semicolon);
-
- ScriptTagImpl scriptTag(Token scriptTag) => ScriptTagImpl(scriptTag);
-
SetOrMapLiteralImpl setOrMapLiteral(
{Token? constKeyword,
TypeArgumentList? typeArguments,
diff --git a/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart b/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
index efcbcd3..4e3f3ed 100644
--- a/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
@@ -158,8 +158,11 @@
typeIdentifier: methodName,
);
} else if (prefixedElement is ExtensionElement) {
- PrefixedIdentifier extensionName =
- astFactory.prefixedIdentifier(target, node.operator!, methodName);
+ PrefixedIdentifier extensionName = PrefixedIdentifierImpl(
+ prefix: target,
+ period: node.operator!,
+ identifier: methodName,
+ );
ExtensionOverride extensionOverride = astFactory.extensionOverride(
extensionName: extensionName,
typeArguments: node.typeArguments,
@@ -481,10 +484,10 @@
required SimpleIdentifierImpl typeIdentifier,
}) {
var typeName = NamedTypeImpl(
- name: astFactory.prefixedIdentifier(
- prefixIdentifier,
- node.operator!,
- typeIdentifier,
+ name: PrefixedIdentifierImpl(
+ prefix: prefixIdentifier,
+ period: node.operator!,
+ identifier: typeIdentifier,
),
typeArguments: node.typeArguments,
question: null,
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index d2c10b9..02d2ed4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/ast/ast_factory.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
@@ -885,16 +884,16 @@
} else {
if (target is SimpleIdentifierImpl &&
target.staticElement is PrefixElement) {
- functionExpression = astFactory.prefixedIdentifier(
- target,
- node.operator!,
- node.methodName,
+ functionExpression = PrefixedIdentifierImpl(
+ prefix: target,
+ period: node.operator!,
+ identifier: node.methodName,
);
} else {
- functionExpression = astFactory.propertyAccess(
- target,
- node.operator!,
- node.methodName,
+ functionExpression = PropertyAccessImpl(
+ target: target,
+ operator: node.operator!,
+ propertyName: node.methodName,
);
}
_resolver.flowAnalysis.flow?.propertyGet(
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
index 9693f8e..106516a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
@@ -38,9 +38,9 @@
_resolver.typeSystem.resolveToBound(prefixType);
if (prefixTypeResolved is RecordType) {
final propertyAccess = PropertyAccessImpl(
- node.prefix,
- node.period,
- node.identifier,
+ target: node.prefix,
+ operator: node.period,
+ propertyName: node.identifier,
);
_resolver.replaceExpression(node, propertyAccess);
return propertyAccess;
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 46bf913..c71aff1 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -408,34 +408,40 @@
}
ConstructorInitializer? buildInitializer(Object initializerObject) {
- if (initializerObject is FunctionExpressionInvocation) {
+ if (initializerObject is FunctionExpressionInvocationImpl) {
Expression function = initializerObject.function;
if (function is SuperExpression) {
return ast.superConstructorInvocation(
function.superKeyword, null, null, initializerObject.argumentList);
}
if (function is ThisExpression) {
- return ast.redirectingConstructorInvocation(
- function.thisKeyword, null, null, initializerObject.argumentList);
+ return RedirectingConstructorInvocationImpl(
+ thisKeyword: function.thisKeyword,
+ period: null,
+ constructorName: null,
+ argumentList: initializerObject.argumentList,
+ );
}
return null;
}
- if (initializerObject is MethodInvocation) {
+ if (initializerObject is MethodInvocationImpl) {
var target = initializerObject.target;
- if (target is SuperExpression) {
+ if (target is SuperExpressionImpl) {
return ast.superConstructorInvocation(
- target.superKeyword,
- initializerObject.operator,
- initializerObject.methodName,
- initializerObject.argumentList);
+ target.superKeyword,
+ initializerObject.operator,
+ initializerObject.methodName,
+ initializerObject.argumentList,
+ );
}
- if (target is ThisExpression) {
- return ast.redirectingConstructorInvocation(
- target.thisKeyword,
- initializerObject.operator,
- initializerObject.methodName,
- initializerObject.argumentList);
+ if (target is ThisExpressionImpl) {
+ return RedirectingConstructorInvocationImpl(
+ thisKeyword: target.thisKeyword,
+ period: initializerObject.operator,
+ constructorName: initializerObject.methodName,
+ argumentList: initializerObject.argumentList,
+ );
}
return buildInitializerTargetExpressionRecovery(
target, initializerObject);
@@ -498,15 +504,15 @@
ConstructorInitializer? buildInitializerTargetExpressionRecovery(
Expression? target, Object initializerObject) {
- ArgumentList? argumentList;
+ ArgumentListImpl? argumentList;
while (true) {
- if (target is FunctionExpressionInvocation) {
+ if (target is FunctionExpressionInvocationImpl) {
argumentList = target.argumentList;
target = target.function;
- } else if (target is MethodInvocation) {
+ } else if (target is MethodInvocationImpl) {
argumentList = target.argumentList;
target = target.target;
- } else if (target is PropertyAccess) {
+ } else if (target is PropertyAccessImpl) {
argumentList = null;
target = target.target;
} else {
@@ -525,8 +531,13 @@
// This error is also reported in the body builder
handleRecoverableError(messageInvalidThisInInitializer,
target.thisKeyword, target.thisKeyword);
- return ast.redirectingConstructorInvocation(target.thisKeyword, null,
- null, argumentList ?? _syntheticArgumentList(target.thisKeyword));
+ return RedirectingConstructorInvocationImpl(
+ thisKeyword: target.thisKeyword,
+ period: null,
+ constructorName: null,
+ argumentList:
+ argumentList ?? _syntheticArgumentList(target.thisKeyword),
+ );
}
return null;
}
@@ -572,13 +583,25 @@
}
void doDotExpression(Token dot) {
- var identifierOrInvoke = pop() as Expression;
- var receiver = pop() as Expression?;
- if (identifierOrInvoke is SimpleIdentifier) {
- if (receiver is SimpleIdentifier && identical('.', dot.stringValue)) {
- push(ast.prefixedIdentifier(receiver, dot, identifierOrInvoke));
+ var identifierOrInvoke = pop() as ExpressionImpl;
+ var receiver = pop() as ExpressionImpl?;
+ if (identifierOrInvoke is SimpleIdentifierImpl) {
+ if (receiver is SimpleIdentifierImpl && identical('.', dot.stringValue)) {
+ push(
+ PrefixedIdentifierImpl(
+ prefix: receiver,
+ period: dot,
+ identifier: identifierOrInvoke,
+ ),
+ );
} else {
- push(ast.propertyAccess(receiver, dot, identifierOrInvoke));
+ push(
+ PropertyAccessImpl(
+ target: receiver,
+ operator: dot,
+ propertyName: identifierOrInvoke,
+ ),
+ );
}
} else if (identifierOrInvoke is MethodInvocationImpl) {
assert(identifierOrInvoke.target == null);
@@ -593,9 +616,15 @@
// upon the type of expression. e.g. "x.this" -> templateThisAsIdentifier
handleRecoverableError(
templateExpectedIdentifier.withArguments(token), token, token);
- SimpleIdentifier identifier =
+ SimpleIdentifierImpl identifier =
ast.simpleIdentifier(token, isDeclaration: false);
- push(ast.propertyAccess(receiver, dot, identifier));
+ push(
+ PropertyAccessImpl(
+ target: receiver,
+ operator: dot,
+ propertyName: identifier,
+ ),
+ );
}
}
@@ -2652,7 +2681,9 @@
assert(optional(';', semicolon));
debugEvent("RethrowStatement");
- final expression = ast.rethrowExpression(rethrowToken);
+ final expression = RethrowExpressionImpl(
+ rethrowKeyword: rethrowToken,
+ );
// TODO(scheglov) According to the specification, 'rethrow' is a statement.
push(
ExpressionStatementImpl(
@@ -2669,8 +2700,14 @@
assert(optional(';', semicolon));
debugEvent("ReturnStatement");
- var expression = hasExpression ? pop() as Expression : null;
- push(ast.returnStatement(returnKeyword, expression, semicolon));
+ var expression = hasExpression ? pop() as ExpressionImpl : null;
+ push(
+ ReturnStatementImpl(
+ returnKeyword: returnKeyword,
+ expression: expression,
+ semicolon: semicolon,
+ ),
+ );
}
@override
@@ -3381,9 +3418,16 @@
) {
var identifier = ast.simpleIdentifier(thirdToken);
if (firstToken != null) {
- var target = ast.prefixedIdentifier(ast.simpleIdentifier(firstToken),
- firstPeriod!, ast.simpleIdentifier(secondToken!));
- var expression = ast.propertyAccess(target, secondPeriod!, identifier);
+ var target = PrefixedIdentifierImpl(
+ prefix: ast.simpleIdentifier(firstToken),
+ period: firstPeriod!,
+ identifier: ast.simpleIdentifier(secondToken!),
+ );
+ var expression = PropertyAccessImpl(
+ target: target,
+ operator: secondPeriod!,
+ propertyName: identifier,
+ );
push(
CommentReferenceImpl(
newKeyword: newKeyword,
@@ -3391,8 +3435,11 @@
),
);
} else if (secondToken != null) {
- var expression = ast.prefixedIdentifier(
- ast.simpleIdentifier(secondToken), secondPeriod!, identifier);
+ var expression = PrefixedIdentifierImpl(
+ prefix: ast.simpleIdentifier(secondToken),
+ period: secondPeriod!,
+ identifier: identifier,
+ );
push(
CommentReferenceImpl(
newKeyword: newKeyword,
@@ -3718,7 +3765,10 @@
var typeName = dot == null
? firstIdentifier
: PrefixedIdentifierImpl(
- firstIdentifier, dot, SimpleIdentifierImpl(secondIdentifierToken!));
+ prefix: firstIdentifier,
+ period: dot,
+ identifier: SimpleIdentifierImpl(secondIdentifierToken!),
+ );
push(
ExtractorPatternImpl(
type: NamedTypeImpl(
@@ -4377,7 +4427,12 @@
startToken: bang,
);
} else {
- push(ast.postfixExpression(pop() as Expression, bang));
+ push(
+ PostfixExpressionImpl(
+ operand: pop() as ExpressionImpl,
+ operator: bang,
+ ),
+ );
}
}
@@ -4472,16 +4527,22 @@
void handleQualified(Token period) {
assert(optional('.', period));
- var identifier = pop() as SimpleIdentifier;
+ var identifier = pop() as SimpleIdentifierImpl;
var prefix = pop();
if (prefix is List) {
// We're just accumulating components into a list.
prefix.add(identifier);
push(prefix);
- } else if (prefix is SimpleIdentifier) {
+ } else if (prefix is SimpleIdentifierImpl) {
// TODO(paulberry): resolve [identifier]. Note that BodyBuilder handles
// this situation using SendAccessGenerator.
- push(ast.prefixedIdentifier(prefix, period, identifier));
+ push(
+ PrefixedIdentifierImpl(
+ prefix: prefix,
+ period: period,
+ identifier: identifier,
+ ),
+ );
} else {
// TODO(paulberry): implement.
logEvent('Qualified with >1 dot');
@@ -4654,7 +4715,9 @@
assert(identical(token.type, TokenType.SCRIPT_TAG));
debugEvent("Script");
- scriptTag = ast.scriptTag(token);
+ scriptTag = ScriptTagImpl(
+ scriptTag: token,
+ );
}
@override
@@ -4793,13 +4856,18 @@
assert(operator.type.isUnaryPostfixOperator);
debugEvent("UnaryPostfixAssignmentExpression");
- var expression = pop() as Expression;
+ var expression = pop() as ExpressionImpl;
if (!expression.isAssignable) {
// This error is also reported by the body builder.
handleRecoverableError(
messageIllegalAssignmentToNonAssignable, operator, operator);
}
- push(ast.postfixExpression(expression, operator));
+ push(
+ PostfixExpressionImpl(
+ operand: expression,
+ operator: operator,
+ ),
+ );
}
@override
@@ -4807,13 +4875,18 @@
assert(operator.type.isUnaryPrefixOperator);
debugEvent("UnaryPrefixAssignmentExpression");
- var expression = pop() as Expression;
+ var expression = pop() as ExpressionImpl;
if (!expression.isAssignable) {
// This error is also reported by the body builder.
handleRecoverableError(messageMissingAssignableSelector,
expression.endToken, expression.endToken);
}
- push(ast.prefixExpression(operator, expression));
+ push(
+ PrefixExpressionImpl(
+ operator: operator,
+ operand: expression,
+ ),
+ );
}
@override
@@ -4821,7 +4894,12 @@
assert(operator.type.isUnaryPrefixOperator);
debugEvent("UnaryPrefixExpression");
- push(ast.prefixExpression(operator, pop() as Expression));
+ push(
+ PrefixExpressionImpl(
+ operator: operator,
+ operand: pop() as ExpressionImpl,
+ ),
+ );
}
@override
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index c71bb61..d8a594a 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1054,9 +1054,9 @@
// TODO(scheglov) It would be nice to rewrite all such cases.
if (prefix.staticType is RecordType) {
final propertyAccess = PropertyAccessImpl(
- prefix,
- node.period,
- node.identifier,
+ target: prefix,
+ operator: node.period,
+ propertyName: node.identifier,
);
NodeReplacer.replace(node, propertyAccess);
return resolveForWrite(
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 7a7596f..4764faf 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -2,10 +2,8 @@
// 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:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/ast_factory.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
@@ -42,12 +40,6 @@
rightHandSide: rightHandSide as ExpressionImpl,
);
- static PropertyAccessImpl cascadedPropertyAccess(String propertyName) =>
- astFactory.propertyAccess(
- null,
- TokenFactory.tokenFromType(TokenType.PERIOD_PERIOD),
- identifier3(propertyName));
-
static ClassDeclarationImpl classDeclaration(
Keyword? abstractKeyword,
String name,
@@ -79,60 +71,6 @@
rightBracket:
TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET));
- static CompilationUnitImpl compilationUnit() =>
- compilationUnit8(null, [], []);
-
- static CompilationUnitImpl compilationUnit2(
- List<CompilationUnitMember> declarations) =>
- compilationUnit8(null, [], declarations);
-
- static CompilationUnitImpl compilationUnit3(List<Directive> directives) =>
- compilationUnit8(null, directives, []);
-
- static CompilationUnitImpl compilationUnit4(List<Directive> directives,
- List<CompilationUnitMember> declarations) =>
- compilationUnit8(null, directives, declarations);
-
- static CompilationUnitImpl compilationUnit5(String scriptTag) =>
- compilationUnit8(scriptTag, [], []);
-
- static CompilationUnitImpl compilationUnit6(
- String scriptTag, List<CompilationUnitMember> declarations) =>
- compilationUnit8(scriptTag, [], declarations);
-
- static CompilationUnitImpl compilationUnit7(
- String scriptTag, List<Directive> directives) =>
- compilationUnit8(scriptTag, directives, []);
-
- static CompilationUnitImpl compilationUnit8(
- String? scriptTag,
- List<Directive> directives,
- List<CompilationUnitMember> declarations) =>
- astFactory.compilationUnit(
- beginToken: TokenFactory.tokenFromType(TokenType.EOF),
- scriptTag:
- scriptTag == null ? null : AstTestFactory.scriptTag(scriptTag),
- directives: directives,
- declarations: declarations,
- endToken: TokenFactory.tokenFromType(TokenType.EOF),
- featureSet: FeatureSet.latestLanguageVersion(),
- lineInfo: LineInfo.fromContent(''));
-
- static CompilationUnitImpl compilationUnit9(
- {String? scriptTag,
- List<Directive> directives = const [],
- List<CompilationUnitMember> declarations = const [],
- required FeatureSet featureSet}) =>
- astFactory.compilationUnit(
- beginToken: TokenFactory.tokenFromType(TokenType.EOF),
- scriptTag:
- scriptTag == null ? null : AstTestFactory.scriptTag(scriptTag),
- directives: directives,
- declarations: declarations,
- endToken: TokenFactory.tokenFromType(TokenType.EOF),
- featureSet: featureSet,
- lineInfo: LineInfo.fromContent(''));
-
static ConstructorDeclarationImpl constructorDeclaration(
Identifier returnType,
String? name,
@@ -247,26 +185,10 @@
null,
TokenFactory.tokenFromType(TokenType.CLOSE_PAREN));
- static PrefixedIdentifierImpl identifier(
- SimpleIdentifier prefix, SimpleIdentifier identifier) =>
- astFactory.prefixedIdentifier(
- prefix, TokenFactory.tokenFromType(TokenType.PERIOD), identifier);
-
static SimpleIdentifierImpl identifier3(String lexeme) =>
astFactory.simpleIdentifier(
TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, lexeme));
- static PrefixedIdentifierImpl identifier4(
- String prefix, SimpleIdentifier identifier) =>
- astFactory.prefixedIdentifier(identifier3(prefix),
- TokenFactory.tokenFromType(TokenType.PERIOD), identifier);
-
- static PrefixedIdentifierImpl identifier5(String prefix, String identifier) =>
- astFactory.prefixedIdentifier(
- identifier3(prefix),
- TokenFactory.tokenFromType(TokenType.PERIOD),
- identifier3(identifier));
-
static List<SimpleIdentifier> identifierList(List<String> identifiers) {
return identifiers
.map((String identifier) => identifier3(identifier))
@@ -443,54 +365,6 @@
semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
);
- static PostfixExpressionImpl postfixExpression(
- Expression expression, TokenType operator) =>
- astFactory.postfixExpression(
- expression, TokenFactory.tokenFromType(operator));
-
- static PrefixExpressionImpl prefixExpression(
- TokenType operator, Expression expression) =>
- astFactory.prefixExpression(
- TokenFactory.tokenFromType(operator), expression);
-
- static PropertyAccessImpl propertyAccess(
- Expression? target, SimpleIdentifier propertyName) =>
- astFactory.propertyAccess(
- target, TokenFactory.tokenFromType(TokenType.PERIOD), propertyName);
-
- static PropertyAccessImpl propertyAccess2(
- Expression? target, String propertyName,
- [TokenType operator = TokenType.PERIOD]) =>
- astFactory.propertyAccess(target, TokenFactory.tokenFromType(operator),
- identifier3(propertyName));
-
- static RedirectingConstructorInvocationImpl redirectingConstructorInvocation(
- [List<Expression> arguments = const []]) =>
- redirectingConstructorInvocation2(null, arguments);
-
- static RedirectingConstructorInvocationImpl redirectingConstructorInvocation2(
- String? constructorName,
- [List<Expression> arguments = const []]) =>
- astFactory.redirectingConstructorInvocation(
- TokenFactory.tokenFromKeyword(Keyword.THIS),
- constructorName == null
- ? null
- : TokenFactory.tokenFromType(TokenType.PERIOD),
- constructorName == null ? null : identifier3(constructorName),
- argumentList(arguments));
-
- static RethrowExpressionImpl rethrowExpression() => astFactory
- .rethrowExpression(TokenFactory.tokenFromKeyword(Keyword.RETHROW));
-
- static ReturnStatementImpl returnStatement() => returnStatement2(null);
-
- static ReturnStatementImpl returnStatement2(Expression? expression) =>
- astFactory.returnStatement(TokenFactory.tokenFromKeyword(Keyword.RETURN),
- expression, TokenFactory.tokenFromType(TokenType.SEMICOLON));
-
- static ScriptTagImpl scriptTag(String scriptTag) =>
- astFactory.scriptTag(TokenFactory.tokenFromString(scriptTag));
-
static SetOrMapLiteralImpl setOrMapLiteral(
Keyword? keyword, TypeArgumentList? typeArguments,
[List<CollectionElement> elements = const []]) =>
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index aee911d..6403ea2 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -941,11 +941,11 @@
}
PostfixExpression _readPostfixExpression() {
- var operand = readNode() as Expression;
+ var operand = readNode() as ExpressionImpl;
var operatorType = UnlinkedTokenType.values[_readByte()];
- var node = astFactory.postfixExpression(
- operand,
- Tokens.fromType(operatorType),
+ var node = PostfixExpressionImpl(
+ operand: operand,
+ operator: Tokens.fromType(operatorType),
);
node.staticElement = _reader.readElement() as MethodElement?;
if (node.operator.type.isIncrementOperator) {
@@ -959,12 +959,12 @@
}
PrefixedIdentifier _readPrefixedIdentifier() {
- var prefix = readNode() as SimpleIdentifier;
- var identifier = readNode() as SimpleIdentifier;
- var node = astFactory.prefixedIdentifier(
- prefix,
- Tokens.period(),
- identifier,
+ var prefix = readNode() as SimpleIdentifierImpl;
+ var identifier = readNode() as SimpleIdentifierImpl;
+ var node = PrefixedIdentifierImpl(
+ prefix: prefix,
+ period: Tokens.period(),
+ identifier: identifier,
);
_readExpressionResolution(node);
return node;
@@ -972,10 +972,10 @@
PrefixExpression _readPrefixExpression() {
var operatorType = UnlinkedTokenType.values[_readByte()];
- var operand = readNode() as Expression;
- var node = astFactory.prefixExpression(
- Tokens.fromType(operatorType),
- operand,
+ var operand = readNode() as ExpressionImpl;
+ var node = PrefixExpressionImpl(
+ operator: Tokens.fromType(operatorType),
+ operand: operand,
);
node.staticElement = _reader.readElement() as MethodElement?;
if (node.operator.type.isIncrementOperator) {
@@ -990,8 +990,8 @@
PropertyAccess _readPropertyAccess() {
var flags = _readByte();
- var target = _readOptionalNode() as Expression?;
- var propertyName = readNode() as SimpleIdentifier;
+ var target = _readOptionalNode() as ExpressionImpl?;
+ var propertyName = readNode() as SimpleIdentifierImpl;
Token operator;
if (AstBinaryFlags.hasQuestion(flags)) {
@@ -1004,7 +1004,11 @@
: Tokens.periodPeriod();
}
- var node = astFactory.propertyAccess(target, operator, propertyName);
+ var node = PropertyAccessImpl(
+ target: target,
+ operator: operator,
+ propertyName: propertyName,
+ );
_readExpressionResolution(node);
return node;
}
@@ -1023,13 +1027,13 @@
}
RedirectingConstructorInvocation _readRedirectingConstructorInvocation() {
- var constructorName = _readOptionalNode() as SimpleIdentifier?;
- var argumentList = readNode() as ArgumentList;
- var node = astFactory.redirectingConstructorInvocation(
- Tokens.this_(),
- constructorName != null ? Tokens.period() : null,
- constructorName,
- argumentList,
+ var constructorName = _readOptionalNode() as SimpleIdentifierImpl?;
+ var argumentList = readNode() as ArgumentListImpl;
+ var node = RedirectingConstructorInvocationImpl(
+ thisKeyword: Tokens.this_(),
+ period: constructorName != null ? Tokens.period() : null,
+ constructorName: constructorName,
+ argumentList: argumentList,
);
node.staticElement = _reader.readElement() as ConstructorElement?;
_resolveNamedExpressions(node.staticElement, node.argumentList);
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index 0e0e0e8..0d80920 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -6,7 +6,6 @@
import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/ast_factory.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
@@ -1378,93 +1377,100 @@
}
void test_isQualified_inPrefixedIdentifier_name() {
- SimpleIdentifier identifier = AstTestFactory.identifier3("test");
- AstTestFactory.identifier4("prefix", identifier);
+ final findNode = _parseStringToFindNode('''
+void f() {
+ prefix.foo;
+}
+''');
+ final identifier = findNode.simple('foo');
expect(identifier.isQualified, isTrue);
}
void test_isQualified_inPrefixedIdentifier_prefix() {
- SimpleIdentifier identifier = AstTestFactory.identifier3("test");
- AstTestFactory.identifier(identifier, AstTestFactory.identifier3("name"));
+ final findNode = _parseStringToFindNode('''
+void f() {
+ prefix.foo;
+}
+''');
+ final identifier = findNode.simple('prefix');
expect(identifier.isQualified, isFalse);
}
void test_isQualified_inPropertyAccess_name() {
- SimpleIdentifier identifier = AstTestFactory.identifier3("test");
- AstTestFactory.propertyAccess(
- AstTestFactory.identifier3("target"), identifier);
+ final findNode = _parseStringToFindNode('''
+void f() {
+ prefix?.foo;
+}
+''');
+ final identifier = findNode.simple('foo');
expect(identifier.isQualified, isTrue);
}
void test_isQualified_inPropertyAccess_target() {
- SimpleIdentifier identifier = AstTestFactory.identifier3("test");
- AstTestFactory.propertyAccess(
- identifier, AstTestFactory.identifier3("name"));
+ final findNode = _parseStringToFindNode('''
+void f() {
+ prefix?.foo;
+}
+''');
+ final identifier = findNode.simple('prefix');
expect(identifier.isQualified, isFalse);
}
void test_isQualified_inReturnStatement() {
- SimpleIdentifier identifier = AstTestFactory.identifier3("test");
- AstTestFactory.returnStatement2(identifier);
+ final findNode = _parseStringToFindNode('''
+void f() {
+ return test;
+}
+''');
+ final identifier = findNode.simple('test');
expect(identifier.isQualified, isFalse);
}
SimpleIdentifier _createIdentifier(
_WrapperKind wrapper, _AssignmentKind assignment) {
- var identifier = AstTestFactory.identifier3("a");
- ExpressionImpl expression = identifier;
- while (true) {
- if (wrapper == _WrapperKind.PREFIXED_LEFT) {
- expression = AstTestFactory.identifier(
- identifier, AstTestFactory.identifier3("_"));
- } else if (wrapper == _WrapperKind.PREFIXED_RIGHT) {
- expression = AstTestFactory.identifier(
- AstTestFactory.identifier3("_"), identifier);
- } else if (wrapper == _WrapperKind.PROPERTY_LEFT) {
- expression = AstTestFactory.propertyAccess2(expression, "_");
- } else if (wrapper == _WrapperKind.PROPERTY_RIGHT) {
- expression = AstTestFactory.propertyAccess(
- AstTestFactory.identifier3("_"), identifier);
- } else {
- throw UnimplementedError();
- }
- break;
+ String code;
+ if (wrapper == _WrapperKind.PREFIXED_LEFT) {
+ code = 'test.right';
+ } else if (wrapper == _WrapperKind.PREFIXED_RIGHT) {
+ code = 'left.test';
+ } else if (wrapper == _WrapperKind.PROPERTY_LEFT) {
+ code = 'test?.right';
+ } else if (wrapper == _WrapperKind.PROPERTY_RIGHT) {
+ code = 'left?.test';
+ } else {
+ throw UnimplementedError();
}
- while (true) {
- if (assignment == _AssignmentKind.BINARY) {
- BinaryExpressionImpl(
- leftOperand: expression,
- operator: TokenFactory.tokenFromType(TokenType.PLUS),
- rightOperand: AstTestFactory.identifier3("_"),
- );
- } else if (assignment == _AssignmentKind.COMPOUND_LEFT) {
- AstTestFactory.assignmentExpression(
- expression, TokenType.PLUS_EQ, AstTestFactory.identifier3("_"));
- } else if (assignment == _AssignmentKind.COMPOUND_RIGHT) {
- AstTestFactory.assignmentExpression(
- AstTestFactory.identifier3("_"), TokenType.PLUS_EQ, expression);
- } else if (assignment == _AssignmentKind.POSTFIX_BANG) {
- AstTestFactory.postfixExpression(expression, TokenType.BANG);
- } else if (assignment == _AssignmentKind.POSTFIX_INC) {
- AstTestFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
- } else if (assignment == _AssignmentKind.PREFIX_DEC) {
- AstTestFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
- } else if (assignment == _AssignmentKind.PREFIX_INC) {
- AstTestFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
- } else if (assignment == _AssignmentKind.PREFIX_NOT) {
- AstTestFactory.prefixExpression(TokenType.BANG, expression);
- } else if (assignment == _AssignmentKind.SIMPLE_LEFT) {
- AstTestFactory.assignmentExpression(
- expression, TokenType.EQ, AstTestFactory.identifier3("_"));
- } else if (assignment == _AssignmentKind.SIMPLE_RIGHT) {
- AstTestFactory.assignmentExpression(
- AstTestFactory.identifier3("_"), TokenType.EQ, expression);
- } else {
- throw UnimplementedError();
- }
- break;
+
+ if (assignment == _AssignmentKind.BINARY) {
+ code = '$code + 0';
+ } else if (assignment == _AssignmentKind.COMPOUND_LEFT) {
+ code = '$code += 0';
+ } else if (assignment == _AssignmentKind.COMPOUND_RIGHT) {
+ code = 'other += $code';
+ } else if (assignment == _AssignmentKind.POSTFIX_BANG) {
+ code = '$code!';
+ } else if (assignment == _AssignmentKind.POSTFIX_INC) {
+ code = '$code++';
+ } else if (assignment == _AssignmentKind.PREFIX_DEC) {
+ code = '--$code';
+ } else if (assignment == _AssignmentKind.PREFIX_INC) {
+ code = '++$code';
+ } else if (assignment == _AssignmentKind.PREFIX_NOT) {
+ code = '!$code';
+ } else if (assignment == _AssignmentKind.SIMPLE_LEFT) {
+ code = '$code = 0';
+ } else if (assignment == _AssignmentKind.SIMPLE_RIGHT) {
+ code = 'other = $code';
+ } else {
+ throw UnimplementedError();
}
- return identifier;
+
+ final findNode = _parseStringToFindNode('''
+void f() {
+ $code;
+}
+''');
+ return findNode.simple('test');
}
/// Return the top-most node in the AST structure containing the given
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index ff1b2d8..3d625a7 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -626,73 +626,65 @@
}
void test_visitCompilationUnit_declaration() {
- _assertSource(
- "var a;",
- AstTestFactory.compilationUnit2([
- AstTestFactory.topLevelVariableDeclaration2(
- Keyword.VAR, [AstTestFactory.variableDeclaration("a")])
- ]));
+ final code = 'var a;';
+ final findNode = _parseStringToFindNode(code);
+ _assertSource(code, findNode.unit);
}
void test_visitCompilationUnit_directive() {
- _assertSource(
- "library l;",
- AstTestFactory.compilationUnit3(
- [AstTestFactory.libraryDirective2("l")]));
+ final code = 'library my;';
+ final findNode = _parseStringToFindNode(code);
+ _assertSource(code, findNode.unit);
}
void test_visitCompilationUnit_directive_declaration() {
- _assertSource(
- "library l; var a;",
- AstTestFactory.compilationUnit4([
- AstTestFactory.libraryDirective2("l")
- ], [
- AstTestFactory.topLevelVariableDeclaration2(
- Keyword.VAR, [AstTestFactory.variableDeclaration("a")])
- ]));
+ final code = 'library my; var a;';
+ final findNode = _parseStringToFindNode(code);
+ _assertSource(code, findNode.unit);
}
void test_visitCompilationUnit_empty() {
- _assertSource("", AstTestFactory.compilationUnit());
+ final code = '';
+ final findNode = _parseStringToFindNode(code);
+ _assertSource(code, findNode.unit);
}
void test_visitCompilationUnit_libraryWithoutName() {
- _assertSource(
- "library ;",
- AstTestFactory.compilationUnit3([AstTestFactory.libraryDirective2(null)]),
- );
+ final code = 'library ;';
+ final findNode = _parseStringToFindNode(code);
+ _assertSource(code, findNode.unit);
}
void test_visitCompilationUnit_script() {
- _assertSource(
- "!#/bin/dartvm", AstTestFactory.compilationUnit5("!#/bin/dartvm"));
+ final findNode = _parseStringToFindNode('''
+#!/bin/dartvm
+''');
+ _assertSource('#!/bin/dartvm', findNode.unit);
}
void test_visitCompilationUnit_script_declaration() {
- _assertSource(
- "!#/bin/dartvm var a;",
- AstTestFactory.compilationUnit6("!#/bin/dartvm", [
- AstTestFactory.topLevelVariableDeclaration2(
- Keyword.VAR, [AstTestFactory.variableDeclaration("a")])
- ]));
+ final findNode = _parseStringToFindNode('''
+#!/bin/dartvm
+var a;
+''');
+ _assertSource('#!/bin/dartvm var a;', findNode.unit);
}
void test_visitCompilationUnit_script_directive() {
- _assertSource(
- "!#/bin/dartvm library l;",
- AstTestFactory.compilationUnit7(
- "!#/bin/dartvm", [AstTestFactory.libraryDirective2("l")]));
+ final findNode = _parseStringToFindNode('''
+#!/bin/dartvm
+library my;
+''');
+ _assertSource('#!/bin/dartvm library my;', findNode.unit);
}
void test_visitCompilationUnit_script_directives_declarations() {
- _assertSource(
- "!#/bin/dartvm library l; var a;",
- AstTestFactory.compilationUnit8("!#/bin/dartvm", [
- AstTestFactory.libraryDirective2("l")
- ], [
- AstTestFactory.topLevelVariableDeclaration2(
- Keyword.VAR, [AstTestFactory.variableDeclaration("a")])
- ]));
+ final findNode = _parseStringToFindNode('''
+#!/bin/dartvm
+library my;
+var a;
+''');
+ _assertSource('#!/bin/dartvm library my; var a;', findNode.unit);
}
void test_visitConditionalExpression() {
@@ -1220,12 +1212,13 @@
}
void test_visitExtensionOverride_prefixedName_noTypeArgs() {
- _assertSource(
- 'p.E(o)',
- AstTestFactory.extensionOverride(
- extensionName: AstTestFactory.identifier5('p', 'E'),
- argumentList: AstTestFactory.argumentList(
- [AstTestFactory.identifier3('o')])));
+ // TODO(scheglov) restore
+ // _assertSource(
+ // 'p.E(o)',
+ // AstTestFactory.extensionOverride(
+ // extensionName: AstTestFactory.identifier5('p', 'E'),
+ // argumentList: AstTestFactory.argumentList(
+ // [AstTestFactory.identifier3('o')])));
}
void test_visitExtensionOverride_prefixedName_typeArgs() {
@@ -2735,10 +2728,13 @@
}
void test_visitPostfixExpression() {
- _assertSource(
- "a++",
- AstTestFactory.postfixExpression(
- AstTestFactory.identifier3("a"), TokenType.PLUS_PLUS));
+ final code = 'a++';
+ var findNode = _parseStringToFindNode('''
+int f() {
+ $code;
+}
+''');
+ _assertSource(code, findNode.postfix(code));
}
void test_visitPostfixPattern() {
@@ -2757,14 +2753,23 @@
}
void test_visitPrefixedIdentifier() {
- _assertSource("a.b", AstTestFactory.identifier5("a", "b"));
+ final code = 'foo.bar';
+ var findNode = _parseStringToFindNode('''
+int f() {
+ $code;
+}
+''');
+ _assertSource(code, findNode.prefixed(code));
}
void test_visitPrefixExpression() {
- _assertSource(
- "-a",
- AstTestFactory.prefixExpression(
- TokenType.MINUS, AstTestFactory.identifier3("a")));
+ final code = '-foo';
+ var findNode = _parseStringToFindNode('''
+int f() {
+ $code;
+}
+''');
+ _assertSource(code, findNode.prefix(code));
}
void test_visitPrefixExpression_precedence() {
@@ -2778,15 +2783,19 @@
}
void test_visitPropertyAccess() {
- _assertSource("a.b",
- AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b"));
+ final code = '(foo).bar';
+ final findNode = _parseStringToFindNode('''
+final x = $code;
+''');
+ _assertSource(code, findNode.propertyAccess(code));
}
void test_visitPropertyAccess_conditional() {
- _assertSource(
- "a?.b",
- AstTestFactory.propertyAccess2(
- AstTestFactory.identifier3("a"), "b", TokenType.QUESTION_PERIOD));
+ final code = 'foo?.bar';
+ final findNode = _parseStringToFindNode('''
+final x = $code;
+''');
+ _assertSource(code, findNode.propertyAccess(code));
}
void test_visitRecordLiteral_mixed() {
@@ -2927,12 +2936,29 @@
}
void test_visitRedirectingConstructorInvocation_named() {
+ final code = 'this.named()';
+ var findNode = _parseStringToFindNode('''
+class A {
+ A() : $code;
+}
+''');
_assertSource(
- "this.c()", AstTestFactory.redirectingConstructorInvocation2("c"));
+ code,
+ findNode.redirectingConstructorInvocation(code),
+ );
}
void test_visitRedirectingConstructorInvocation_unnamed() {
- _assertSource("this()", AstTestFactory.redirectingConstructorInvocation());
+ final code = 'this()';
+ var findNode = _parseStringToFindNode('''
+class A {
+ A.named() : $code;
+}
+''');
+ _assertSource(
+ code,
+ findNode.redirectingConstructorInvocation(code),
+ );
}
void test_visitRelationalPattern() {
@@ -2951,21 +2977,35 @@
}
void test_visitRethrowExpression() {
- _assertSource("rethrow", AstTestFactory.rethrowExpression());
+ final code = 'rethrow';
+ var findNode = _parseStringToFindNode('''
+void f() {
+ try {} on int {
+ $code;
+ }
+}
+''');
+ _assertSource(code, findNode.rethrow_(code));
}
void test_visitReturnStatement_expression() {
- _assertSource("return a;",
- AstTestFactory.returnStatement2(AstTestFactory.identifier3("a")));
+ final code = 'return 0;';
+ var findNode = _parseStringToFindNode('''
+int f() {
+ $code
+}
+''');
+ _assertSource(code, findNode.returnStatement(code));
}
void test_visitReturnStatement_noExpression() {
- _assertSource("return;", AstTestFactory.returnStatement());
- }
-
- void test_visitScriptTag() {
- String scriptTag = "!#/bin/dart.exe";
- _assertSource(scriptTag, AstTestFactory.scriptTag(scriptTag));
+ final code = 'return;';
+ var findNode = _parseStringToFindNode('''
+int f() {
+ $code
+}
+''');
+ _assertSource(code, findNode.returnStatement(code));
}
void test_visitSetOrMapLiteral_map_complex() {
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index b88f904..0c507ad 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -2304,6 +2304,24 @@
return false;
}
+ // Records
+ //
+ // TODO(50081): Reference rules to updated specification
+ // https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
+ //
+ // TODO(50081): record is subtype of interface `Record`.
+ if (s is RecordType) {
+ if (t is! RecordType) return false;
+ if (s.shape != t.shape) return false;
+ List<DartType> sFields = s.fields;
+ List<DartType> tFields = t.fields;
+ assert(sFields.length == tFields.length); // Guaranteed by shape.
+ for (int i = 0; i < sFields.length; i++) {
+ if (!_isSubtype(sFields[i], tFields[i], env)) return false;
+ }
+ return true;
+ }
+
return false;
}
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 911f72f..a15fa13 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -742,6 +742,12 @@
}
@override
+ EvaluationComplexity visitRecordType(ir.RecordType node) {
+ EvaluationComplexity complexity = visitNodes(node.positional);
+ return complexity.combine(visitNodes(node.named));
+ }
+
+ @override
EvaluationComplexity visitFutureOrType(ir.FutureOrType node) {
return visitNode(node.typeArgument);
}
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
index b0c071f..ec2818d 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -294,8 +294,19 @@
@override
void visitRecordType(RecordType type, _) {
- // TODO(49718): Implement Rti recipes for records.
- throw UnimplementedError();
+ _emitCode(Recipe.startRecord);
+ // Partial shape tag. The full shape is this plus the number of fields.
+ _emitStringUnescaped(type.shape.fieldNames.join(Recipe.separatorString));
+ _emitCode(Recipe.startFunctionArguments);
+ bool first = true;
+ for (DartType field in type.fields) {
+ if (!first) {
+ _emitCode(Recipe.separator);
+ }
+ visit(field, _);
+ first = false;
+ }
+ _emitCode(Recipe.endFunctionArguments);
}
@override
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index 1659004..5a3cf51 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -101,6 +101,15 @@
}
@override
+ void visitRecordType(
+ ir.RecordType node, List<ir.TypeParameter> functionTypeVariables) {
+ _sink.writeEnum(DartTypeNodeKind.recordType);
+ _sink.writeEnum(node.declaredNullability);
+ visitTypes(node.positional, functionTypeVariables);
+ _visitNamedTypes(node.named, functionTypeVariables);
+ }
+
+ @override
void visitFutureOrType(
ir.FutureOrType node, List<ir.TypeParameter> functionTypeVariables) {
_sink.writeEnum(DartTypeNodeKind.futureOrType);
@@ -125,13 +134,18 @@
_sink.writeEnum(node.nullability);
_sink.writeInt(node.requiredParameterCount);
visitTypes(node.positionalParameters, functionTypeVariables);
- _sink.writeInt(node.namedParameters.length);
- for (ir.NamedType parameter in node.namedParameters) {
+ _visitNamedTypes(node.namedParameters, functionTypeVariables);
+ _sink.end(functionTypeNodeTag);
+ }
+
+ void _visitNamedTypes(
+ List<ir.NamedType> named, List<ir.TypeParameter> functionTypeVariables) {
+ _sink.writeInt(named.length);
+ for (ir.NamedType parameter in named) {
_sink.writeString(parameter.name);
_sink.writeBool(parameter.isRequired);
_sink._writeDartTypeNode(parameter.type, functionTypeVariables);
}
- _sink.end(functionTypeNodeTag);
}
@override
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index 5194f8b..1d3ce24 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -882,14 +882,7 @@
int requiredParameterCount = readInt();
List<ir.DartType> positionalParameters =
_readDartTypeNodes(functionTypeVariables);
- int namedParameterCount = readInt();
- final namedParameters =
- List<ir.NamedType>.generate(namedParameterCount, (index) {
- String name = readString();
- bool isRequired = readBool();
- ir.DartType type = _readDartTypeNode(functionTypeVariables)!;
- return ir.NamedType(name, type, isRequired: isRequired);
- }, growable: false);
+ final namedParameters = _readNamedTypeNodes(functionTypeVariables);
end(functionTypeNodeTag);
return ir.FunctionType(positionalParameters, returnType, nullability,
namedParameters: namedParameters,
@@ -914,6 +907,12 @@
List<ir.DartType> typeArguments =
_readDartTypeNodes(functionTypeVariables);
return ExactInterfaceType(cls, nullability, typeArguments);
+ case DartTypeNodeKind.recordType:
+ ir.Nullability nullability = readEnum(ir.Nullability.values);
+ List<ir.DartType> positional =
+ _readDartTypeNodes(functionTypeVariables);
+ List<ir.NamedType> named = _readNamedTypeNodes(functionTypeVariables);
+ return ir.RecordType(positional, named, nullability);
case DartTypeNodeKind.typedef:
ir.Typedef typedef = readTypedefNode();
ir.Nullability nullability = readEnum(ir.Nullability.values);
@@ -931,6 +930,18 @@
}
}
+ List<ir.NamedType> _readNamedTypeNodes(
+ List<ir.TypeParameter> functionTypeVariables) {
+ int count = readInt();
+ if (count == 0) return const [];
+ return List<ir.NamedType>.generate(count, (index) {
+ String name = readString();
+ bool isRequired = readBool();
+ ir.DartType type = _readDartTypeNode(functionTypeVariables)!;
+ return ir.NamedType(name, type, isRequired: isRequired);
+ }, growable: false);
+ }
+
/// Reads a list of kernel type nodes from this data source.
///
/// This is a convenience method to be used together with
diff --git a/pkg/compiler/lib/src/serialization/tags.dart b/pkg/compiler/lib/src/serialization/tags.dart
index 34db060..b40781f 100644
--- a/pkg/compiler/lib/src/serialization/tags.dart
+++ b/pkg/compiler/lib/src/serialization/tags.dart
@@ -85,6 +85,7 @@
functionType,
functionTypeVariable,
interfaceType,
+ recordType,
typedef,
dynamicType,
invalidType,
diff --git a/pkg/js_shared/lib/synced/recipe_syntax.dart b/pkg/js_shared/lib/synced/recipe_syntax.dart
index 51b8358..03d4958 100644
--- a/pkg/js_shared/lib/synced/recipe_syntax.dart
+++ b/pkg/js_shared/lib/synced/recipe_syntax.dart
@@ -58,6 +58,9 @@
static const String genericFunctionTypeParameterIndexString =
_circumflexString;
+ static const int startRecord = _plus;
+ static const String startRecordString = _plusString;
+
static const int extensionOp = _ampersand;
static const String extensionOpString = _ampersandString;
static const int pushNeverExtension = 0;
@@ -198,6 +201,7 @@
requiredNameSeparatorString);
test("genericFunctionTypeParameterIndex", genericFunctionTypeParameterIndex,
genericFunctionTypeParameterIndexString);
+ test("startRecord", startRecord, startRecordString);
test("extensionOp", extensionOp, extensionOpString);
testExtension(
"pushNeverExtension", pushNeverExtension, pushNeverExtensionString);
diff --git a/sdk/lib/_internal/js_shared/lib/rti.dart b/sdk/lib/_internal/js_shared/lib/rti.dart
index c14ebbf..1241c45 100644
--- a/sdk/lib/_internal/js_shared/lib/rti.dart
+++ b/sdk/lib/_internal/js_shared/lib/rti.dart
@@ -184,9 +184,10 @@
static const int kindInterface = 9;
// A vector of type parameters from enclosing functions and closures.
static const int kindBinding = 10;
- static const int kindFunction = 11;
- static const int kindGenericFunction = 12;
- static const int kindGenericFunctionParameter = 13;
+ static const int kindRecord = 11;
+ static const int kindFunction = 12;
+ static const int kindGenericFunction = 13;
+ static const int kindGenericFunctionParameter = 14;
static bool _isUnionOfFunctionType(Rti rti) {
int kind = Rti._getKind(rti);
@@ -202,6 +203,8 @@
/// - Underlying type for unary terms.
/// - Class part of a type environment inside a generic class, or `null` for
/// type tuple.
+ /// - A tag that, together with the number of fields, distinguishes the shape
+ /// of a record type.
/// - Return type of a function type.
/// - Underlying function type for a generic function.
/// - de Bruijn index for a generic function parameter.
@@ -217,6 +220,7 @@
/// - The type arguments of an interface type.
/// - The type arguments from enclosing functions and closures for a
/// kindBinding.
+ /// - The field types of a record type.
/// - The [_FunctionParameters] of a function type.
/// - The type parameter bounds of a generic function.
Object? _rest;
@@ -248,6 +252,16 @@
return JS('JSUnmodifiableArray', '#', _getRest(rti));
}
+ static String _getRecordPartialShapeTag(Rti rti) {
+ assert(_getKind(rti) == kindRecord);
+ return _Utils.asString(_getPrimary(rti));
+ }
+
+ static JSArray _getRecordFields(Rti rti) {
+ assert(_getKind(rti) == kindRecord);
+ return JS('JSUnmodifiableArray', '#', _getRest(rti));
+ }
+
static Rti _getStarArgument(Rti rti) {
assert(_getKind(rti) == kindStar);
return _Utils.asRti(_getPrimary(rti));
@@ -1270,6 +1284,37 @@
return s;
}
+String _recordRtiToString(Rti recordType, List<String>? genericContext) {
+ // For correctness of subtyping, the partial shape tag could be any encoding
+ // that maps different sets of names to different tags.
+ //
+ // Here we assume that the tag is a comma-separated list of names for the last
+ // N named fields.
+ String partialShape = Rti._getRecordPartialShapeTag(recordType);
+ Object? fields = Rti._getRecordFields(recordType);
+ if ('' == partialShape) {
+ // No named fields.
+ return '(' + _rtiArrayToString(fields, genericContext) + ')';
+ }
+
+ int fieldCount = _Utils.arrayLength(fields);
+ Object names = _Utils.stringSplit(partialShape, ',');
+ int namesIndex = _Utils.arrayLength(names) - fieldCount; // Can be negative.
+
+ String s = '(', comma = '';
+ for (int i = 0; i < fieldCount; i++) {
+ s += comma;
+ comma = ', ';
+ if (namesIndex == 0) s += '{';
+ s += _rtiToString(_Utils.asRti(_Utils.arrayAt(fields, i)), genericContext);
+ if (namesIndex >= 0) {
+ s += ' ' + _Utils.asString(_Utils.arrayAt(names, namesIndex));
+ }
+ namesIndex++;
+ }
+ return s + '})';
+}
+
String _functionRtiToString(Rti functionType, List<String>? genericContext,
{Object? bounds = null}) {
String typeParametersText = '';
@@ -1416,6 +1461,10 @@
return name;
}
+ if (kind == Rti.kindRecord) {
+ return _recordRtiToString(rti, genericContext);
+ }
+
if (kind == Rti.kindFunction) {
return _functionRtiToString(rti, genericContext);
}
@@ -2049,6 +2098,36 @@
return _installTypeTests(universe, rti);
}
+ static String _canonicalRecipeOfRecord(
+ String partialShapeTag, Object? fields) {
+ return _recipeJoin5(
+ Recipe.startRecordString,
+ partialShapeTag,
+ Recipe.startFunctionArgumentsString,
+ _canonicalRecipeJoin(fields),
+ Recipe.endFunctionArgumentsString);
+ }
+
+ static Rti _lookupRecordRti(
+ Object? universe, String partialShapeTag, Object? fields) {
+ String key = _canonicalRecipeOfRecord(partialShapeTag, fields);
+ var cache = evalCache(universe);
+ var probe = _Utils.mapGet(cache, key);
+ if (probe != null) return _Utils.asRti(probe);
+ return _installRti(universe, key,
+ _createRecordRti(universe, partialShapeTag, fields, key));
+ }
+
+ static Rti _createRecordRti(
+ Object? universe, String partialShapeTag, Object? fields, String key) {
+ Rti rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindRecord);
+ Rti._setPrimary(rti, partialShapeTag);
+ Rti._setRest(rti, fields);
+ Rti._setCanonicalRecipe(rti, key);
+ return _installTypeTests(universe, rti);
+ }
+
static String _canonicalRecipeOfFunction(
Rti returnType, _FunctionParameters parameters) =>
_recipeJoin(Rti._getCanonicalRecipe(returnType),
@@ -2413,11 +2492,12 @@
break;
case Recipe.startFunctionArguments:
+ push(stack, gotoFunction);
pushStackFrame(parser, stack);
break;
case Recipe.endFunctionArguments:
- handleFunctionArguments(parser, stack);
+ handleArguments(parser, stack);
break;
case Recipe.startOptionalGroup:
@@ -2436,6 +2516,10 @@
handleNamedGroup(parser, stack);
break;
+ case Recipe.startRecord:
+ i = handleStartRecord(parser, i, source, stack);
+ break;
+
default:
JS('', 'throw "Bad character " + #', ch);
}
@@ -2511,24 +2595,40 @@
}
}
- static const int optionalPositionalSentinel = -1;
- static const int namedSentinel = -2;
+ static const int optionalPositionalMarker = -1;
+ static const int namedMarker = -2;
+ static const int gotoFunction = -3;
+ static const int gotoRecord = -4;
- static void handleFunctionArguments(Object? parser, Object? stack) {
+ static void handleArguments(Object? parser, Object? stack) {
var universe = _Parser.universe(parser);
- _FunctionParameters parameters = _FunctionParameters.allocate();
- Object? optionalPositional = _Universe.sharedEmptyArray(universe);
- Object? named = _Universe.sharedEmptyArray(universe);
+ Object? optionalPositional;
+ Object? named;
+
+ // Parse the stack into a function type or a record type. A 'goto' marker is
+ // on the stack to distinguish between records and functions (similar to the
+ // GOTO table of an LR parser), and a marker tag is used for optional and
+ // named argument groups.
+ //
+ // Function types:
+ //
+ // R -3 <pos> T1 ... Tn -> R(T1,...,Tn)
+ // R -3 <pos> T1 ... Tn optional -1 -> R(T1,...,Tn, [optional...])
+ // R -3 <pos> T1 ... Tn named -2 -> R(T1,...,Tn, {named...}])
+ //
+ // Record types:
+ //
+ // shapeToken -4 <pos> T1 ... Tn -> (T1,...,Tn) with shapeToken
var head = pop(stack);
if (_Utils.isNum(head)) {
int sentinel = _Utils.asInt(head);
switch (sentinel) {
- case optionalPositionalSentinel:
+ case optionalPositionalMarker:
optionalPositional = pop(stack);
break;
- case namedSentinel:
+ case namedMarker:
named = pop(stack);
break;
@@ -2540,24 +2640,62 @@
push(stack, head);
}
- _FunctionParameters._setRequiredPositional(
- parameters, collectArray(parser, stack));
- _FunctionParameters._setOptionalPositional(parameters, optionalPositional);
- _FunctionParameters._setNamed(parameters, named);
- Rti returnType = toType(universe, environment(parser), pop(stack));
- push(stack, _Universe._lookupFunctionRti(universe, returnType, parameters));
+ Object? requiredPositional = collectArray(parser, stack);
+
+ head = pop(stack);
+ switch (head) {
+ case gotoFunction:
+ head = pop(stack);
+ optionalPositional ??= _Universe.sharedEmptyArray(universe);
+ named ??= _Universe.sharedEmptyArray(universe);
+ Rti returnType = toType(universe, environment(parser), head);
+ _FunctionParameters parameters = _FunctionParameters.allocate();
+ _FunctionParameters._setRequiredPositional(
+ parameters, requiredPositional);
+ _FunctionParameters._setOptionalPositional(
+ parameters, optionalPositional);
+ _FunctionParameters._setNamed(parameters, named);
+ push(stack,
+ _Universe._lookupFunctionRti(universe, returnType, parameters));
+ return;
+
+ case gotoRecord:
+ assert(optionalPositional == null);
+ assert(named == null);
+ head = pop(stack);
+ assert(_Utils.isString(head));
+ push(
+ stack,
+ _Universe._lookupRecordRti(
+ universe, _Utils.asString(head), requiredPositional));
+ return;
+
+ default:
+ throw AssertionError('Unexpected state under `()`: $head');
+ }
}
static void handleOptionalGroup(Object? parser, Object? stack) {
var parameters = collectArray(parser, stack);
push(stack, parameters);
- push(stack, optionalPositionalSentinel);
+ push(stack, optionalPositionalMarker);
}
static void handleNamedGroup(Object? parser, Object? stack) {
var parameters = collectNamed(parser, stack);
push(stack, parameters);
- push(stack, namedSentinel);
+ push(stack, namedMarker);
+ }
+
+ static int handleStartRecord(
+ Object? parser, int start, String source, Object? stack) {
+ int end = _Utils.stringIndexOf(
+ source, Recipe.startFunctionArgumentsString, start);
+ assert(end >= 0);
+ push(stack, _Utils.substring(source, start, end));
+ push(stack, gotoRecord);
+ pushStackFrame(parser, stack);
+ return end + 1;
}
static void handleExtendedOperations(Object? parser, Object? stack) {
@@ -2861,6 +2999,17 @@
return _isInterfaceSubtype(universe, s, sEnv, t, tEnv);
}
+ // Records
+ //
+ // TODO(50081): Reference rules to updated specification
+ // https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md#rules
+ //
+ // TODO(50081): record is subtype of interface `Record`.
+ if (sKind == Rti.kindRecord) {
+ if (tKind != Rti.kindRecord) return false;
+ return _isRecordSubtype(universe, s, sEnv, t, tEnv);
+ }
+
return false;
}
@@ -3058,6 +3207,29 @@
return true;
}
+bool _isRecordSubtype(
+ Object? universe, Rti s, Object? sEnv, Rti t, Object? tEnv) {
+ // `s` is a subtype of `t` if `s` and `t` have the same shape and the fields
+ // of `s` are pairwise subtypes of the fields of `t`.
+ final sFields = Rti._getRecordFields(s);
+ final tFields = Rti._getRecordFields(t);
+ int sCount = _Utils.arrayLength(sFields);
+ int tCount = _Utils.arrayLength(tFields);
+ if (sCount != tCount) return false;
+ String sTag = Rti._getRecordPartialShapeTag(s);
+ String tTag = Rti._getRecordPartialShapeTag(t);
+ if (sTag != tTag) return false;
+
+ for (int i = 0; i < sCount; i++) {
+ Rti sField = _Utils.asRti(_Utils.arrayAt(sFields, i));
+ Rti tField = _Utils.asRti(_Utils.arrayAt(tFields, i));
+ if (!_isSubtype(universe, sField, sEnv, tField, tEnv)) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool isNullable(Rti t) {
int kind = Rti._getKind(t);
return isNullType(t) ||
@@ -3153,9 +3325,15 @@
static JSArray arrayConcat(Object? a1, Object? a2) =>
JS('JSArray', '#.concat(#)', a1, a2);
+ static JSArray stringSplit(String s, String pattern) =>
+ JS('JSArray', '#.split(#)', s, pattern);
+
static String substring(String s, int start, int end) =>
JS('String', '#.substring(#, #)', s, start, end);
+ static int stringIndexOf(String s, String pattern, int start) =>
+ JS('int', '#.indexOf(#, #)', s, pattern, start);
+
static bool stringLessThan(String s1, String s2) =>
JS('bool', '# < #', s1, s2);
diff --git a/sdk/lib/_internal/js_shared/lib/synced/recipe_syntax.dart b/sdk/lib/_internal/js_shared/lib/synced/recipe_syntax.dart
index 51b8358..03d4958 100644
--- a/sdk/lib/_internal/js_shared/lib/synced/recipe_syntax.dart
+++ b/sdk/lib/_internal/js_shared/lib/synced/recipe_syntax.dart
@@ -58,6 +58,9 @@
static const String genericFunctionTypeParameterIndexString =
_circumflexString;
+ static const int startRecord = _plus;
+ static const String startRecordString = _plusString;
+
static const int extensionOp = _ampersand;
static const String extensionOpString = _ampersandString;
static const int pushNeverExtension = 0;
@@ -198,6 +201,7 @@
requiredNameSeparatorString);
test("genericFunctionTypeParameterIndex", genericFunctionTypeParameterIndex,
genericFunctionTypeParameterIndexString);
+ test("startRecord", startRecord, startRecordString);
test("extensionOp", extensionOp, extensionOpString);
testExtension(
"pushNeverExtension", pushNeverExtension, pushNeverExtensionString);
diff --git a/sdk/lib/_internal/wasm/lib/async_patch.dart b/sdk/lib/_internal/wasm/lib/async_patch.dart
index 68d64d1..7c6c4b0 100644
--- a/sdk/lib/_internal/wasm/lib/async_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/async_patch.dart
@@ -86,8 +86,13 @@
@pragma("wasm:entry-point")
Object? _awaitHelper(Object? operand, WasmExternRef? stack) {
+ // Save the existing zone in a local, and restore('_leave') upon returning. We
+ // ensure that the zone will be restored in the event of an exception by
+ // restoring the original zone before we throw the exception.
+ _Zone current = Zone._current;
if (operand is! Future) return operand;
Object? result = _futurePromise(stack, operand);
+ Zone._leave(current);
if (result is _FutureError) {
// TODO(askesc): Combine stack traces
throw result.exception;
diff --git a/tools/VERSION b/tools/VERSION
index 77b5cb5..15b4dc6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 19
PATCH 0
-PRERELEASE 280
+PRERELEASE 281
PRERELEASE_PATCH 0