Version 2.17.0-233.0.dev
Merge commit '727a35c588adaf45817226225f77debf903e8f73' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 4d8dd70..fa954ae 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -580,7 +580,7 @@
"name": "shelf",
"rootUri": "../third_party/pkg/shelf",
"packageUri": "lib/",
- "languageVersion": "2.12"
+ "languageVersion": "2.16"
},
{
"name": "shelf_packages_handler",
diff --git a/DEPS b/DEPS
index 8153c4c..98aeeab 100644
--- a/DEPS
+++ b/DEPS
@@ -148,7 +148,7 @@
"shelf_static_rev": "202ec1a53c9a830c17cf3b718d089cf7eba568ad",
"shelf_packages_handler_rev": "78302e67c035047e6348e692b0c1182131f0fe35",
"shelf_proxy_tag": "ccd311f64d8689e7a145d703ba267975d6df9e28", # 1.0.0
- "shelf_rev": "46483f896cc4308ee3d8e997030ae799b72aa16a",
+ "shelf_rev": "78ac724a7944700340a3cef28c84bccbe62e9367",
"shelf_web_socket_rev": "24fb8a04befa75a94ac63a27047b231d1a22aab4",
"source_map_stack_trace_rev": "80709f2d2fe5086ab50d744a28a2d26ea4384a1b",
"source_maps-0.9.4_rev": "38524",
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index e4718a0..e5e361b 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
name: _fe_analyzer_shared
-version: 36.0.0
+version: 37.0.0
description: Logic that is shared between the front_end and analyzer packages.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/_fe_analyzer_shared
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 41043e5..1ea1e2e 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -1,28 +1,42 @@
# This file contains a map. The key of each top-level entry is the unique name
-# of either an error code or a lint name. The value of each top-level entry is
-# a map describing the status of fixes related to that diagnostic.
+# of an error code. The value of each top-level entry is a map describing the
+# status of fixes related to that diagnostic.
#
# In every second-level map, the first key is `status` and the corresponding
# value is one of the following:
-# - needsEvaluation, if the diagnostic has not been evaluated in terms of fixes.
-# - hasFix, if the diagnostic has one or more fixes.
-# - noFix, if no fix seems appropriate for the diagnostic. There should be a
+# - 'needsEvaluation', if the diagnostic has not been evaluated in terms of
+# fixes.
+# - 'hasFix', if the diagnostic has one or more fixes.
+# - 'noFix', if no fix seems appropriate for the diagnostic. There should be a
# second key named `reason` whose value is text explaining why there is no
# appropriate fix.
-# - needsFix, if the diagnostic needs a fix, with a possible issue link. If an
+# - 'needsFix', if the diagnostic needs a fix, with a possible issue link. If an
# issue has been opened, there should be a second key named `issue` whose
# value is the URL of the issue.
#
+# The other keys in the second-level map are all optional, and include
+# - 'since', whose value is the version number of the SDK in which the
+# diagnostic was added.
+# - 'notes', whose value is text, typically describing why we think a fix for
+# the diagnostic is not appropriate.
+# - 'issue', whose value is a list of the URLs of GitHub issues for the fixes
+# that should be added. Ideally every issue marked as 'needFix' would have an
+# issue created for it.
+#
# Stats:
-# - 809 "needsEvaluation"
-# - 19 "needsFix"
-# - 253 "hasFix"
-# - 3 "noFix"
+# - 759 "needsEvaluation"
+# - 32 "needsFix"
+# - 265 "hasFix"
+# - 41 "noFix"
AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR:
status: noFix
+ notes: |-
+ The fix needs to be made in the included file.
AnalysisOptionsErrorCode.PARSE_ERROR:
status: noFix
+ notes: |-
+ There isn't enough information to be able to provide a fix.
AnalysisOptionsHintCode.PREVIEW_DART_2_SETTING_DEPRECATED:
status: needsEvaluation
AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED:
@@ -32,11 +46,22 @@
AnalysisOptionsWarningCode.ANALYSIS_OPTION_DEPRECATED:
status: needsEvaluation
AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ It would not be performant to search the disk for analysis options files
+ that could be included.
+
+ We could potentially have a fix to create the referenced file that currently
+ doesn't exist.
AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ The fix needs to be made in the included file.
AnalysisOptionsWarningCode.INVALID_OPTION:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ We could look for valid options that are similar to the invalid option and
+ replace the invalid option with the selected replacement.
AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT:
status: needsEvaluation
AnalysisOptionsWarningCode.SPEC_MODE_REMOVED:
@@ -276,6 +301,7 @@
status: needsEvaluation
CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR:
status: hasFix
+ issue: https://github.com/dart-lang/sdk/issues/48644
CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR:
status: needsEvaluation
CompileTimeErrorCode.DEFAULT_VALUE_ON_REQUIRED_PARAMETER:
@@ -560,7 +586,8 @@
status: needsEvaluation
CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_SET:
status: needsEvaluation
-CompileTimeErrorCode.INVALID_URI: needsEvaluation
+CompileTimeErrorCode.INVALID_URI:
+ status: needsEvaluation
CompileTimeErrorCode.INVALID_USE_OF_COVARIANT:
status: needsEvaluation
CompileTimeErrorCode.INVALID_USE_OF_NULL_VALUE:
@@ -1141,9 +1168,13 @@
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH:
status: needsEvaluation
HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ Fix depends on user's intent, which can't be known.
HintCode.ASSIGNMENT_OF_DO_NOT_STORE:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ Fix depends on user's intent, which can't be known.
HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE:
status: hasFix
HintCode.CAN_BE_NULL_AFTER_NULL_AWARE:
@@ -1155,21 +1186,33 @@
HintCode.DEAD_CODE_ON_CATCH_SUBTYPE:
status: hasFix
HintCode.DEPRECATED_EXTENDS_FUNCTION:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ The fix is to remove `Function` from where it's referenced.
HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ The fix is to rename the class, which can't be done as a fix.
HintCode.DEPRECATED_IMPLEMENTS_FUNCTION:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ The fix is to remove `Function` from where it's referenced.
HintCode.DEPRECATED_MEMBER_USE:
status: hasFix
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ Should probably be able to use `DataDriven`.
HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ Should probably be able to use `DataDriven`.
HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE:
status: hasFix
HintCode.DEPRECATED_MIXIN_FUNCTION:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ The fix is to remove `Function` from where it's referenced.
HintCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE:
status: hasFix
HintCode.DIVISION_OPTIMIZATION:
@@ -1177,19 +1220,29 @@
HintCode.DUPLICATE_HIDDEN_NAME:
status: hasFix
HintCode.DUPLICATE_IGNORE:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ One fix is to remove the duplicated error code.
HintCode.DUPLICATE_IMPORT:
status: hasFix
HintCode.DUPLICATE_SHOWN_NAME:
status: hasFix
HintCode.EQUAL_ELEMENTS_IN_SET:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ Fix depends on user's intent, which can't be known.
HintCode.EQUAL_KEYS_IN_MAP:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ Fix depends on user's intent, which can't be known.
HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE:
- status: needsEvaluation
+ status: noFix
+ notes: |-
+ Fix depends on user's intent, which can't be known.
HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE:
- status: needsEvaluation
+ status: needsFix
+ notes: |-
+ One fix is to convert the reference to a 'package:' URI.
HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION:
status: needsEvaluation
HintCode.IMPORT_OF_LEGACY_LIBRARY_INTO_NULL_SAFE:
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 10fc9e5..9fb3607 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -874,6 +874,7 @@
ChangeTo.classOrMixin,
],
CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR: [
+ ConvertToListLiteral.newInstance,
ReplaceWithFilled.newInstance,
],
CompileTimeErrorCode.EXTENDS_NON_CLASS: [
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart
index a74a556..31b6596 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_list_literal_test.dart
@@ -13,6 +13,7 @@
defineReflectiveSuite(() {
defineReflectiveTests(ConvertToListLiteralBulkTest);
defineReflectiveTests(ConvertToListLiteralTest);
+ defineReflectiveTests(ConvertToListLiteralWithNullSafetyTest);
});
}
@@ -80,3 +81,18 @@
''');
}
}
+
+@reflectiveTest
+class ConvertToListLiteralWithNullSafetyTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_LIST_LITERAL;
+
+ Future<void> test_default() async {
+ await resolveTestCode('''
+final l = List();
+''');
+ await assertHasFix('''
+final l = [];
+''');
+ }
+}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 5c1cf47..0c4a820 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 3.4.0-dev
+## 3.4.0
* Deprecated `Resource.parent2`, use `parent` instead.
* Deprecated `astFactory`, clients should not create AST nodes manually.
* Changed `CompilationUnit.lineInfo` to be non-nullable.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 0a0a1e6..fcbceef 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1237,6 +1237,10 @@
/// invoke an undefined method on an object.
static final String NO_SUCH_METHOD_METHOD_NAME = "noSuchMethod";
+ /// Return `true` if this function represents `identical` from the
+ /// `dart:core` library.
+ bool get isDartCoreIdentical;
+
/// Return `true` if the function is an entry point, i.e. a top-level function
/// and has the name `main`.
bool get isEntryPoint;
diff --git a/pkg/analyzer/lib/src/dart/constant/potentially_constant.dart b/pkg/analyzer/lib/src/dart/constant/potentially_constant.dart
index 66503bc..6c13da9 100644
--- a/pkg/analyzer/lib/src/dart/constant/potentially_constant.dart
+++ b/pkg/analyzer/lib/src/dart/constant/potentially_constant.dart
@@ -269,9 +269,9 @@
void _methodInvocation(MethodInvocation node) {
var arguments = node.argumentList.arguments;
- if (arguments.length == 2 && node.methodName.name == 'identical') {
- var library = node.methodName.staticElement?.library;
- if (library?.isDartCore == true) {
+ if (arguments.length == 2) {
+ var element = node.methodName.staticElement;
+ if (element is FunctionElement && element.isDartCoreIdentical) {
collect(arguments[0]);
collect(arguments[1]);
return;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 8a9ab33..d33f063 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -3349,6 +3349,11 @@
}
@override
+ bool get isDartCoreIdentical {
+ return isStatic && name == 'identical' && library.isDartCore;
+ }
+
+ @override
bool get isEntryPoint {
return isStatic && displayName == FunctionElement.MAIN_FUNCTION_NAME;
}
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index f6195f1..8d8f03d 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -419,6 +419,9 @@
Element get enclosingElement => declaration.enclosingElement;
@override
+ bool get isDartCoreIdentical => declaration.isDartCoreIdentical;
+
+ @override
bool get isEntryPoint => declaration.isEntryPoint;
@override
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index 46980c7..2c9c197 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -31,7 +31,7 @@
AnnotationImpl node,
ClassElement classElement,
SimpleIdentifierImpl? constructorName,
- ArgumentList argumentList,
+ ArgumentListImpl argumentList,
List<WhyNotPromotedGetter> whyNotPromotedList,
) {
ConstructorElement? constructorElement;
@@ -98,7 +98,7 @@
SimpleIdentifierImpl? constructorName,
List<TypeParameterElement> typeParameters,
ConstructorElement? constructorElement,
- ArgumentList argumentList,
+ ArgumentListImpl argumentList,
InterfaceType Function(List<DartType> typeArguments) instantiateElement,
List<WhyNotPromotedGetter> whyNotPromotedList,
) {
@@ -116,6 +116,7 @@
annotationInferrer.resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: argumentList,
rawType: null,
contextType: null,
whyNotPromotedList: whyNotPromotedList);
@@ -131,6 +132,7 @@
annotationInferrer.resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: argumentList,
rawType: constructorRawType,
contextType: null,
whyNotPromotedList: whyNotPromotedList);
@@ -338,7 +340,7 @@
TypeAliasElement typeAliasElement,
SimpleIdentifierImpl? constructorName,
InterfaceType aliasedType,
- ArgumentList argumentList,
+ ArgumentListImpl argumentList,
List<WhyNotPromotedGetter> whyNotPromotedList,
) {
var constructorElement = aliasedType.lookUpConstructor(
@@ -402,6 +404,7 @@
AnnotationInferrer(constructorName: null).resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: arguments,
rawType: null,
contextType: null,
whyNotPromotedList: whyNotPromotedList);
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index ddbdfdb..d345b15 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -119,6 +119,7 @@
const FunctionExpressionInvocationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: rawType,
whyNotPromotedList: whyNotPromotedList,
contextType: contextType,
@@ -208,6 +209,7 @@
const FunctionExpressionInvocationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: null,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList);
diff --git a/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
index bfdf73f..74c6873 100644
--- a/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
@@ -65,6 +65,7 @@
const InstanceCreationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: elementToInfer?.asType,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList);
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 038cc4f..4112fcde 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -173,6 +173,7 @@
var returnType = const MethodInvocationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: rawType,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList,
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
index c8117fd..a2c3b09 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inferrer.dart
@@ -36,9 +36,6 @@
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
@override
- ArgumentListImpl _getArgumentList(AnnotationImpl node) => node.arguments!;
-
- @override
bool _getIsConst(AnnotationImpl node) => true;
@override
@@ -66,21 +63,10 @@
}
/// Specialization of [InvocationInferrer] for performing type inference on AST
-/// nodes of type [ExtensionOverride].
-class ExtensionOverrideInferrer
- extends InvocationInferrer<ExtensionOverrideImpl> {
- const ExtensionOverrideInferrer() : super._();
-
- @override
- ArgumentListImpl _getArgumentList(ExtensionOverrideImpl node) =>
- node.argumentList;
-}
-
-/// Specialization of [InvocationInferrer] for performing type inference on AST
/// nodes that require full downward and upward inference.
abstract class FullInvocationInferrer<Node extends AstNodeImpl>
extends InvocationInferrer<Node> {
- const FullInvocationInferrer._() : super._();
+ const FullInvocationInferrer._();
bool get _needsTypeArgumentBoundsCheck => false;
@@ -91,6 +77,7 @@
DartType resolveInvocation({
required ResolverVisitor resolver,
required Node node,
+ required ArgumentListImpl argumentList,
required FunctionType? rawType,
required DartType? contextType,
required List<WhyNotPromotedGetter> whyNotPromotedList,
@@ -175,37 +162,31 @@
super.resolveInvocation(
resolver: resolver,
node: node,
+ argumentList: argumentList,
rawType: invokeType,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList);
- var argumentList = _getArgumentList(node);
-
if (inferrer != null) {
- if (rawType != null) {
- // Get the parameters that correspond to the uninstantiated generic.
- List<ParameterElement?> rawParameters =
- ResolverVisitor.resolveArgumentsToParameters(
- argumentList: argumentList,
- parameters: rawType.parameters,
- );
+ // Get the parameters that correspond to the uninstantiated generic.
+ List<ParameterElement?> rawParameters =
+ ResolverVisitor.resolveArgumentsToParameters(
+ argumentList: argumentList,
+ parameters: rawType!.parameters,
+ );
- List<ParameterElement> params = <ParameterElement>[];
- List<DartType> argTypes = <DartType>[];
- for (int i = 0, length = rawParameters.length; i < length; i++) {
- ParameterElement? parameter = rawParameters[i];
- if (parameter != null) {
- params.add(parameter);
- argTypes.add(argumentList.arguments[i].typeOrThrow);
- }
+ List<ParameterElement> params = <ParameterElement>[];
+ List<DartType> argTypes = <DartType>[];
+ for (int i = 0, length = rawParameters.length; i < length; i++) {
+ ParameterElement? parameter = rawParameters[i];
+ if (parameter != null) {
+ params.add(parameter);
+ argTypes.add(argumentList.arguments[i].typeOrThrow);
}
- inferrer.constrainArguments(
- parameters: params, argumentTypes: argTypes);
- typeArgumentTypes = inferrer.upwardsInfer();
- invokeType = rawType.instantiate(typeArgumentTypes);
- } else {
- typeArgumentTypes = const [];
}
+ inferrer.constrainArguments(parameters: params, argumentTypes: argTypes);
+ typeArgumentTypes = inferrer.upwardsInfer();
+ invokeType = rawType.instantiate(typeArgumentTypes);
}
var parameters = _storeResult(node, typeArgumentTypes, invokeType);
@@ -276,10 +257,6 @@
bool get _needsTypeArgumentBoundsCheck => true;
@override
- ArgumentListImpl _getArgumentList(InstanceCreationExpressionImpl node) =>
- node.argumentList;
-
- @override
ConstructorNameImpl _getErrorNode(InstanceCreationExpressionImpl node) =>
node.constructorName;
@@ -327,9 +304,6 @@
const InvocationExpressionInferrer._() : super._();
@override
- ArgumentListImpl _getArgumentList(Node node) => node.argumentList;
-
- @override
Expression _getErrorNode(Node node) => node.function;
@override
@@ -346,8 +320,11 @@
/// Base class containing functionality for performing type inference on AST
/// nodes that invoke a method, function, or constructor.
-abstract class InvocationInferrer<Node extends AstNodeImpl> {
- const InvocationInferrer._();
+///
+/// This class may be used directly for inference of [ExtensionOverride],
+/// [RedirectingConstructorInvocation], or [SuperConstructorInvocation].
+class InvocationInferrer<Node extends AstNodeImpl> {
+ const InvocationInferrer();
/// Performs type inference on an invocation expression of type [Node].
/// [rawType] should be the type of the function the invocation is resolved to
@@ -355,6 +332,7 @@
void resolveInvocation({
required ResolverVisitor resolver,
required Node node,
+ required ArgumentListImpl argumentList,
required FunctionType? rawType,
required DartType? contextType,
required List<WhyNotPromotedGetter> whyNotPromotedList,
@@ -369,7 +347,6 @@
}
}
}
- var argumentList = _getArgumentList(node);
resolver.checkUnreachableNode(argumentList);
var flow = resolver.flowAnalysis.flow;
var positionalParameterIndex = 0;
@@ -419,9 +396,6 @@
DartType parameterType, DartType? methodInvocationContext) =>
parameterType;
- /// Gets the argument list for the invocation. TODO(paulberry): remove?
- ArgumentListImpl _getArgumentList(Node node);
-
/// Determines whether [node] is an invocation of the core function
/// `identical` (which needs special flow analysis treatment).
bool _isIdentical(Node node) => false;
@@ -466,8 +440,7 @@
bool _isIdentical(MethodInvocationImpl node) {
var invokedMethod = node.methodName.staticElement;
return invokedMethod is FunctionElement &&
- invokedMethod.name == 'identical' &&
- invokedMethod.library.isDartCore &&
+ invokedMethod.isDartCoreIdentical &&
node.argumentList.arguments.length == 2;
}
@@ -488,26 +461,3 @@
return returnType;
}
}
-
-/// Specialization of [InvocationInferrer] for performing type inference on AST
-/// nodes of type [RedirectingConstructorInvocation].
-class RedirectingConstructorInvocationInferrer
- extends InvocationInferrer<RedirectingConstructorInvocationImpl> {
- const RedirectingConstructorInvocationInferrer() : super._();
-
- @override
- ArgumentListImpl _getArgumentList(
- RedirectingConstructorInvocationImpl node) =>
- node.argumentList;
-}
-
-/// Specialization of [InvocationInferrer] for performing type inference on AST
-/// nodes of type [SuperConstructorInvocation].
-class SuperConstructorInvocationInferrer
- extends InvocationInferrer<SuperConstructorInvocationImpl> {
- const SuperConstructorInvocationInferrer() : super._();
-
- @override
- ArgumentListImpl _getArgumentList(SuperConstructorInvocationImpl node) =>
- node.argumentList;
-}
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 776d654..ebfd7d4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -332,6 +332,7 @@
.resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: rawType is FunctionType ? rawType : null,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList);
@@ -476,6 +477,7 @@
const MethodInvocationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: rawType,
whyNotPromotedList: whyNotPromotedList,
contextType: contextType);
@@ -549,6 +551,7 @@
const MethodInvocationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: null,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList);
@@ -568,6 +571,7 @@
const MethodInvocationInferrer().resolveInvocation(
resolver: _resolver,
node: node,
+ argumentList: node.argumentList,
rawType: null,
contextType: contextType,
whyNotPromotedList: whyNotPromotedList);
diff --git a/pkg/analyzer/lib/src/error/use_result_verifier.dart b/pkg/analyzer/lib/src/error/use_result_verifier.dart
index f0a60a8..a54515c 100644
--- a/pkg/analyzer/lib/src/error/use_result_verifier.dart
+++ b/pkg/analyzer/lib/src/error/use_result_verifier.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
@@ -157,23 +158,56 @@
}
}
- if (parent is ParenthesizedExpression ||
+ if (parent is PostfixExpression) {
+ if (parent.operator.type == TokenType.BANG) {
+ // Null-checking a result is not a "use."
+ return _isUsed(parent);
+ } else {
+ // Other uses, like `++`, count as a "use."
+ return true;
+ }
+ }
+
+ if (parent is AwaitExpression ||
parent is ConditionalExpression ||
- parent is AwaitExpression) {
+ parent is ForElement ||
+ parent is IfElement ||
+ parent is ParenthesizedExpression ||
+ parent is SpreadElement) {
return _isUsed(parent);
}
+ if (parent is ForParts) {
+ // If [node] is the condition of a for-loop, it is used; if it is one of
+ // the updaters, it is not.
+ return parent.condition == node;
+ }
+
return parent is ArgumentList ||
- // Node should always be RHS so no need to check for a property assignment.
+ parent is AssertInitializer ||
+ parent is AssertStatement ||
+ // Node should always be RHS so no need to check for a property
+ // assignment.
parent is AssignmentExpression ||
- parent is VariableDeclaration ||
+ parent is BinaryExpression ||
+ parent is ConstructorFieldInitializer ||
+ parent is DoStatement ||
+ parent is ExpressionFunctionBody ||
+ parent is ForEachParts ||
+ parent is ForLoopParts ||
+ parent is FunctionExpressionInvocation ||
+ parent is IfStatement ||
+ parent is IndexExpression ||
+ parent is ListLiteral ||
+ parent is MapLiteralEntry ||
parent is MethodInvocation ||
parent is PropertyAccess ||
- parent is ExpressionFunctionBody ||
parent is ReturnStatement ||
- parent is FunctionExpressionInvocation ||
- parent is ListLiteral ||
parent is SetOrMapLiteral ||
- parent is MapLiteralEntry;
+ parent is SwitchStatement ||
+ parent is ThrowExpression ||
+ parent is VariableDeclaration ||
+ parent is WhileStatement ||
+ parent is YieldStatement;
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1c07741..6b2ba66 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1540,9 +1540,10 @@
var receiverContextType =
ExtensionMemberResolver(this).computeOverrideReceiverContextType(node);
- const ExtensionOverrideInferrer().resolveInvocation(
+ const InvocationInferrer<ExtensionOverrideImpl>().resolveInvocation(
resolver: this,
node: node,
+ argumentList: node.argumentList,
rawType: receiverContextType == null
? null
: FunctionTypeImpl(
@@ -2163,12 +2164,14 @@
var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
elementResolver.visitRedirectingConstructorInvocation(
node as RedirectingConstructorInvocationImpl);
- const RedirectingConstructorInvocationInferrer().resolveInvocation(
- resolver: this,
- node: node,
- rawType: node.staticElement?.type,
- contextType: null,
- whyNotPromotedList: whyNotPromotedList);
+ const InvocationInferrer<RedirectingConstructorInvocationImpl>()
+ .resolveInvocation(
+ resolver: this,
+ node: node,
+ argumentList: node.argumentList,
+ rawType: node.staticElement?.type,
+ contextType: null,
+ whyNotPromotedList: whyNotPromotedList);
checkForArgumentTypesNotAssignableInList(
node.argumentList, whyNotPromotedList);
}
@@ -2271,12 +2274,14 @@
var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
elementResolver.visitSuperConstructorInvocation(
node as SuperConstructorInvocationImpl);
- const SuperConstructorInvocationInferrer().resolveInvocation(
- resolver: this,
- node: node,
- rawType: node.staticElement?.type,
- contextType: null,
- whyNotPromotedList: whyNotPromotedList);
+ const InvocationInferrer<SuperConstructorInvocationImpl>()
+ .resolveInvocation(
+ resolver: this,
+ node: node,
+ argumentList: node.argumentList,
+ rawType: node.staticElement?.type,
+ contextType: null,
+ whyNotPromotedList: whyNotPromotedList);
checkForArgumentTypesNotAssignableInList(
node.argumentList, whyNotPromotedList);
}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 24b3c13..c740b60 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 3.4.0-dev
+version: 3.4.0
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
@@ -7,7 +7,7 @@
sdk: '>=2.14.0 <3.0.0'
dependencies:
- _fe_analyzer_shared: ^36.0.0
+ _fe_analyzer_shared: ^37.0.0
collection: ^1.15.0
convert: ^3.0.0
crypto: ^3.0.0
diff --git a/pkg/analyzer/test/src/diagnostics/unused_result_test.dart b/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
index 812bf13..1954c47 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
@@ -497,6 +497,37 @@
]);
}
+ test_method_result_assertInitializer() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+class B {
+ B(A a) :
+ assert(a.foo() != 7);
+}
+''');
+ }
+
+ test_method_result_assertStatement() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+void f(A a) {
+ assert(a.foo() != 7);
+}
+''');
+ }
+
test_method_result_assigned() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -513,6 +544,234 @@
''');
}
+ test_method_result_binaryExpression() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+void f(A a) {
+ 1 + a.foo();
+}
+''');
+ }
+
+ test_method_result_conditional() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ bool foo() => false;
+}
+
+void f(A a) {
+ if (a.foo()) {}
+}
+''');
+ }
+
+ test_method_result_constructorCall() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+class B {
+ B(int i);
+}
+
+void f(A a) {
+ new B(a.foo());
+}
+''');
+ }
+
+ test_method_result_doWhile() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ bool foo() => false;
+}
+
+void f(A a) {
+ do {}
+ while (a.foo());
+}
+''');
+ }
+
+ test_method_result_fieldInitializer() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+class B {
+ int i;
+ B(A a) : i = a.foo();
+}
+''');
+ }
+
+ test_method_result_for() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+void f(A a) {
+ for (var i = 1; i < a.foo(); i++) {}
+}
+''');
+ }
+
+ test_method_result_for_updaters() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+void f(A a) {
+ for (var i = 1; i < 7; a.foo()) {}
+}
+''', [
+ error(HintCode.UNUSED_RESULT, 119, 3),
+ ]);
+ }
+
+ test_method_result_forElement() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ List<int> foo() => [];
+}
+
+void f(A a) {
+ // Note that the list literal is unused, but we unconditionally consider use
+ // within a list literal to be "use of result."
+ [
+ for (var e in a.foo()) e,
+ ];
+}
+''');
+ }
+
+ test_method_result_forIn() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ List<int> foo() => [];
+}
+
+void f(A a) {
+ for (var _ in a.foo()) {}
+}
+''');
+ }
+
+ test_method_result_ifElement() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ bool foo() => false;
+}
+
+void f(A a) {
+ // Note that the list literal is unused, but we unconditionally consider use
+ // within a list literal to be "use of result."
+ [
+ if (a.foo()) 1,
+ ];
+}
+''');
+ }
+
+ test_method_result_ifNull() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int? foo() => 1;
+}
+
+int f(A a) {
+ return a.foo() ?? 7;
+}
+''');
+ }
+
+ test_method_result_indexExpression() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+void f(A a, List<int> list) {
+ list[a.foo()];
+}
+''');
+ }
+
+ test_method_result_nullCheck_isUsed() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int? foo() => 1;
+}
+
+int f(A a) {
+ return a.foo()!;
+}
+''');
+ }
+
+ test_method_result_nullCheck_notUsed() async {
+ await assertErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int? foo() => 1;
+}
+
+void f(A a) {
+ a.foo()!;
+}
+''', [
+ error(HintCode.UNUSED_RESULT, 97, 3),
+ ]);
+ }
+
test_method_result_passed() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -544,6 +803,57 @@
''');
}
+ test_method_result_spread() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ List<int> foo() => [];
+}
+
+void f(A a) {
+ // Note that the list literal is unused, but we unconditionally consider use
+ // within a list literal to be "use of result."
+ [...a.foo()];
+}
+''');
+ }
+
+ test_method_result_superInitializer() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+class B {
+ B(int i);
+}
+
+class C extends B {
+ C(A a) : super(a.foo());
+}
+''');
+ }
+
+ test_method_result_switchCondition() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ bool foo() => false;
+}
+
+void f(A a) {
+ switch (a.foo()) {}
+}
+''');
+ }
+
test_method_result_targetedMethod() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -572,6 +882,21 @@
''');
}
+ test_method_result_thrown() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ bool foo() => false;
+}
+
+void f(A a) {
+ throw a.foo();
+}
+''');
+ }
+
test_method_result_unassigned() async {
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -639,6 +964,36 @@
''');
}
+ test_method_result_while() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ bool foo() => false;
+}
+
+void f(A a) {
+ while (a.foo()) {}
+}
+''');
+ }
+
+ test_method_result_yield() async {
+ await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ @useResult
+ int foo() => 1;
+}
+
+Stream<int> f(A a) async* {
+ yield a.foo();
+}
+''');
+ }
+
test_topLevelFunction_result_assigned() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index c6e7a5e..b25e1c4 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -70,8 +70,10 @@
final String name;
final CompilerOptions? options;
+ final bool canPerformGlobalTransforms;
- Dart2jsTarget(this.name, this.flags, {this.options});
+ Dart2jsTarget(this.name, this.flags,
+ {this.options, this.canPerformGlobalTransforms = true});
@override
bool get enableNoSuchMethodForwarders => true;
@@ -157,8 +159,10 @@
}
lowering.transformLibraries(libraries, coreTypes, hierarchy, options);
logger?.call("Lowering transformations performed");
- transformMixins.transformLibraries(libraries);
- logger?.call("Mixin transformations performed");
+ if (canPerformGlobalTransforms) {
+ transformMixins.transformLibraries(libraries);
+ logger?.call("Mixin transformations performed");
+ }
}
@override
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 3f926b2..18d2044 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -170,9 +170,7 @@
bool get fromDill {
var targetPath = compilationTarget!.path;
- return targetPath.endsWith('.dill') ||
- targetPath.endsWith('.gdill') ||
- targetPath.endsWith('.mdill');
+ return targetPath.endsWith('.dill');
}
/// Location of the package configuration file.
diff --git a/pkg/compiler/lib/src/phase/load_kernel.dart b/pkg/compiler/lib/src/phase/load_kernel.dart
index 17795f7..44314a7 100644
--- a/pkg/compiler/lib/src/phase/load_kernel.dart
+++ b/pkg/compiler/lib/src/phase/load_kernel.dart
@@ -17,6 +17,8 @@
import '../common.dart';
import '../kernel/front_end_adapter.dart';
import '../kernel/dart2js_target.dart' show Dart2jsTarget;
+import '../kernel/transformations/clone_mixin_methods_with_super.dart'
+ as transformMixins show transformLibraries;
import '../options.dart';
class Input {
@@ -121,6 +123,10 @@
this.component, this.entryLibrary, this.moduleLibraries);
}
+void _doGlobalTransforms(Component component) {
+ transformMixins.transformLibraries(component.libraries);
+}
+
Future<_LoadFromKernelResult> _loadFromKernel(CompilerOptions options,
api.CompilerInput compilerInput, String targetName) async {
Library entryLibrary;
@@ -178,6 +184,11 @@
var mainMethod = _findMainMethod(entryLibrary);
component.setMainMethodAndMode(mainMethod, true, component.mode);
}
+
+ // We apply global transforms when running phase 0.
+ if (options.cfeOnly) {
+ _doGlobalTransforms(component);
+ }
return _LoadFromKernelResult(component, entryLibrary, moduleLibraries);
}
@@ -195,7 +206,8 @@
fe.InitializedCompilerState initializedCompilerState,
String targetName) async {
bool verbose = false;
- Target target = Dart2jsTarget(targetName, TargetFlags(), options: options);
+ Target target = Dart2jsTarget(targetName, TargetFlags(),
+ options: options, canPerformGlobalTransforms: true);
fe.FileSystem fileSystem = CompilerFileSystem(compilerInput);
fe.Verbosity verbosity = options.verbosity;
fe.DiagnosticMessageHandler onDiagnostic = (fe.DiagnosticMessage message) {
diff --git a/pkg/compiler/tool/modular_test_suite.dart b/pkg/compiler/tool/modular_test_suite.dart
index 7a20a67..cf0d52c 100644
--- a/pkg/compiler/tool/modular_test_suite.dart
+++ b/pkg/compiler/tool/modular_test_suite.dart
@@ -23,6 +23,7 @@
OutlineDillCompilationStep(),
FullDillCompilationStep(),
ModularAnalysisStep(),
+ ConcatenateDillsStep(useModularAnalysis: true),
ComputeClosedWorldStep(useModularAnalysis: true),
GlobalAnalysisStep(),
Dart2jsCodegenStep(codeId0),
diff --git a/pkg/compiler/tool/modular_test_suite_helper.dart b/pkg/compiler/tool/modular_test_suite_helper.dart
index d4ff09e..357b1da 100644
--- a/pkg/compiler/tool/modular_test_suite_helper.dart
+++ b/pkg/compiler/tool/modular_test_suite_helper.dart
@@ -25,13 +25,14 @@
String _dart2jsScript;
String _kernelWorkerScript;
-const dillSummaryId = DataId("sdill");
-const dillId = DataId("dill");
-const modularUpdatedDillId = DataId("mdill");
-const modularDataId = DataId("mdata");
+const dillSummaryId = DataId("summary.dill");
+const dillId = DataId("full.dill");
+const fullDillId = DataId("concatenate.dill");
+const modularUpdatedDillId = DataId("modular.dill");
+const modularDataId = DataId("modular.data");
const closedWorldId = DataId("world");
-const globalUpdatedDillId = DataId("gdill");
-const globalDataId = DataId("gdata");
+const globalUpdatedDillId = DataId("global.dill");
+const globalDataId = DataId("global.data");
const codeId = ShardsDataId("code", 2);
const codeId0 = ShardDataId(codeId, 0);
const codeId1 = ShardDataId(codeId, 1);
@@ -305,44 +306,36 @@
}
}
-DataId idForDill({bool useModularAnalysis}) =>
- useModularAnalysis ? modularUpdatedDillId : dillId;
-
-List<DataId> inputFromAnalysis({bool useModularAnalysis = false}) => [
- idForDill(useModularAnalysis: useModularAnalysis),
- if (useModularAnalysis) modularDataId,
- ];
-
-// Step that invokes the dart2js closed world computation.
-class ComputeClosedWorldStep implements IOModularStep {
+class ConcatenateDillsStep implements IOModularStep {
final bool useModularAnalysis;
- ComputeClosedWorldStep({this.useModularAnalysis});
+ DataId get idForDill => useModularAnalysis ? modularUpdatedDillId : dillId;
+
+ List<DataId> get dependencies => [idForDill];
@override
- List<DataId> get resultData => const [closedWorldId, globalUpdatedDillId];
+ List<DataId> get resultData => const [fullDillId];
@override
bool get needsSources => false;
@override
- List<DataId> get dependencyDataNeeded =>
- inputFromAnalysis(useModularAnalysis: useModularAnalysis);
+ List<DataId> get dependencyDataNeeded => dependencies;
@override
- List<DataId> get moduleDataNeeded =>
- inputFromAnalysis(useModularAnalysis: useModularAnalysis);
+ List<DataId> get moduleDataNeeded => dependencies;
@override
bool get onlyOnMain => true;
+ ConcatenateDillsStep({this.useModularAnalysis});
+
@override
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
List<String> flags) async {
- if (_options.verbose)
- print("\nstep: dart2js compute closed world on $module");
+ if (_options.verbose) print("\nstep: dart2js concatenate dills on $module");
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
- DataId dillId = idForDill(useModularAnalysis: useModularAnalysis);
+ DataId dillId = idForDill;
Iterable<String> dillDependencies =
transitiveDependencies.map((m) => '${toUri(m, dillId)}');
List<String> dataDependencies = transitiveDependencies
@@ -358,8 +351,66 @@
'${Flags.inputDill}=${toUri(module, dillId)}',
for (String flag in flags) '--enable-experiment=$flag',
'${Flags.dillDependencies}=${dillDependencies.join(',')}',
- if (useModularAnalysis)
- '${Flags.readModularAnalysis}=${dataDependencies.join(',')}',
+ '${Flags.cfeOnly}',
+ '--out=${toUri(module, fullDillId)}',
+ ];
+ var result =
+ await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
+
+ _checkExitCode(result, this, module);
+ }
+
+ @override
+ void notifyCached(Module module) {
+ if (_options.verbose)
+ print("\ncached step: dart2js concatenate dills on $module");
+ }
+}
+
+// Step that invokes the dart2js closed world computation.
+class ComputeClosedWorldStep implements IOModularStep {
+ final bool useModularAnalysis;
+
+ ComputeClosedWorldStep({this.useModularAnalysis});
+
+ List<DataId> get dependencies => [
+ fullDillId,
+ if (useModularAnalysis) modularDataId,
+ ];
+
+ @override
+ List<DataId> get resultData => const [closedWorldId, globalUpdatedDillId];
+
+ @override
+ bool get needsSources => false;
+
+ @override
+ List<DataId> get dependencyDataNeeded => dependencies;
+
+ @override
+ List<DataId> get moduleDataNeeded => dependencies;
+
+ @override
+ bool get onlyOnMain => true;
+
+ @override
+ Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
+ List<String> flags) async {
+ if (_options.verbose)
+ print("\nstep: dart2js compute closed world on $module");
+ Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
+ List<String> dataDependencies = transitiveDependencies
+ .map((m) => '${toUri(m, modularDataId)}')
+ .toList();
+ dataDependencies.add('${toUri(module, modularDataId)}');
+ List<String> args = [
+ '--packages=${sdkRoot.toFilePath()}/.packages',
+ _dart2jsScript,
+ // TODO(sigmund): remove this dependency on libraries.json
+ if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+ '${Flags.entryUri}=$fakeRoot${module.mainSource}',
+ '${Flags.inputDill}=${toUri(module, fullDillId)}',
+ for (String flag in flags) '--enable-experiment=$flag',
'${Flags.writeClosedWorld}=${toUri(module, closedWorldId)}',
Flags.noClosedWorldInData,
'--out=${toUri(module, globalUpdatedDillId)}',
diff --git a/pkg/compiler/tool/modular_test_suite_legacy.dart b/pkg/compiler/tool/modular_test_suite_legacy.dart
index 875a64a..f170069 100644
--- a/pkg/compiler/tool/modular_test_suite_legacy.dart
+++ b/pkg/compiler/tool/modular_test_suite_legacy.dart
@@ -22,6 +22,7 @@
IOPipeline([
OutlineDillCompilationStep(),
FullDillCompilationStep(),
+ ConcatenateDillsStep(useModularAnalysis: false),
ComputeClosedWorldStep(useModularAnalysis: false),
GlobalAnalysisStep(),
Dart2jsCodegenStep(codeId0),
diff --git a/pkg/compiler/tool/szcmp b/pkg/compiler/tool/szcmp
new file mode 100755
index 0000000..1b2db57
--- /dev/null
+++ b/pkg/compiler/tool/szcmp
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+# Usage: szcmp files
+#
+# Compare sizes of files as percentages in a table. Column header is the
+# baseline (i.e. all sizes in the column are in terms of the file in the column
+# header).
+#
+# Example with dart2js workflow:
+#
+# $ dart2js ... --out=v1/m.js
+# # change dart2js
+# $ dart2js ... --out=v2/m.js
+# # change dart2js again
+# $ dart2js ... --out=v3/m.js
+#
+# $ szcmp v?/m.js
+# v1/m.js v2/m.js v3/m.js
+# 5793879 v1/m.js = -4.499% +4.461%
+# 6066812 v2/m.js +4.711% = +9.382%
+# 5546433 v3/m.js -4.271% -8.577% =
+#
+# The first column of the matrix is usually the most relevant - `v2` is 4.7%
+# larger than `v1` and `v3` is 4.2% smaller than `v1`. The other columns can be
+# useful for understanding the differential changes. Sizes relative to `v2` are
+# in the next column, e.g. the step from `v2` to `v3` was a reduction of
+# 8.6%. Above-diagonal values show the percentage change in the 'undo'
+# direction. While changing from `v2` to `v3` reduces by 8.6%, reverting that
+# change would be an increase of 9.4%.
+
+wc -c "$@" |
+awk '
+$2 == "total" { next; }
+
+{
+ N++
+ r[N,0] = $1;
+ r[N,1] = $2;
+}
+
+END {
+ r[0,0] = "" # header col 0
+ r[0,1] = "" # header col 1
+
+ for (i = 1; i <= N; i++) { #skips "total" line
+ r[0, i+1] = r[i,1] # name header
+
+ for (j = 1; j <= N; j++) {
+ s1 = r[i,0]
+ s2 = r[j,0];
+ if (s1 == s2) {
+ r[i, j+1] = "="
+ } else {
+ x = sprintf("%.3f%%", (s1 - s2) / s2 * 100)
+ if (s1 > s2) x = "+" x
+ r[i, j+1] = x
+ }
+ }
+ }
+
+ # find column widths
+ for (cc = 0; cc <= N+1; cc++) {
+ w[cc] = 0;
+ for (rr = 0; rr <= N; rr++) {
+ if (length(r[rr,cc]) > w[cc]) w[cc] = length(r[rr,cc])
+ }
+ }
+
+ for (rr = 0; rr <= N; rr++) {
+ line = ""
+ sep = ""
+ for (cc = 0; cc <= N+1; cc++) {
+ line = line sep sprintf("%*s", w[cc], r[rr, cc])
+ sep = " "
+ }
+ print line
+ }
+}
+'
diff --git a/pkg/js_ast/analysis_options.yaml b/pkg/js_ast/analysis_options.yaml
new file mode 100644
index 0000000..a1888bc
--- /dev/null
+++ b/pkg/js_ast/analysis_options.yaml
@@ -0,0 +1,16 @@
+# Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+analyzer:
+ errors:
+ todo: ignore
+ # Allow deprecated calls from within the same package
+ deprecated_member_use_from_same_package: ignore
+
+linter:
+ rules:
+ - annotate_overrides
+ - prefer_final_fields
+ - prefer_if_null_operators
+ - prefer_null_aware_operators
diff --git a/pkg/js_ast/lib/src/builder.dart b/pkg/js_ast/lib/src/builder.dart
index 83bb11f..7774925 100644
--- a/pkg/js_ast/lib/src/builder.dart
+++ b/pkg/js_ast/lib/src/builder.dart
@@ -356,6 +356,7 @@
final MiniJsParser parser;
final String message;
+ @override
String toString() {
int pos = parser.lastPosition;
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 7c62eab..06330a1 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -89,118 +89,185 @@
const BaseVisitor();
T visitNode(Node node);
+ @override
T visitComment(Comment node);
+ @override
T visitProgram(Program node) => visitNode(node);
T visitStatement(Statement node) => visitNode(node);
T visitLoop(Loop node) => visitStatement(node);
T visitJump(Statement node) => visitStatement(node);
+ @override
T visitBlock(Block node) => visitStatement(node);
+ @override
T visitExpressionStatement(ExpressionStatement node) => visitStatement(node);
+ @override
T visitEmptyStatement(EmptyStatement node) => visitStatement(node);
+ @override
T visitIf(If node) => visitStatement(node);
+ @override
T visitFor(For node) => visitLoop(node);
+ @override
T visitForIn(ForIn node) => visitLoop(node);
+ @override
T visitWhile(While node) => visitLoop(node);
+ @override
T visitDo(Do node) => visitLoop(node);
+ @override
T visitContinue(Continue node) => visitJump(node);
+ @override
T visitBreak(Break node) => visitJump(node);
+ @override
T visitReturn(Return node) => visitJump(node);
+ @override
T visitThrow(Throw node) => visitJump(node);
+ @override
T visitTry(Try node) => visitStatement(node);
+ @override
T visitSwitch(Switch node) => visitStatement(node);
+ @override
T visitFunctionDeclaration(FunctionDeclaration node) => visitStatement(node);
+ @override
T visitLabeledStatement(LabeledStatement node) => visitStatement(node);
+ @override
T visitLiteralStatement(LiteralStatement node) => visitStatement(node);
+ @override
T visitCatch(Catch node) => visitNode(node);
+ @override
T visitCase(Case node) => visitNode(node);
+ @override
T visitDefault(Default node) => visitNode(node);
T visitExpression(Expression node) => visitNode(node);
T visitVariableReference(VariableReference node) => visitExpression(node);
+ @override
T visitLiteralExpression(LiteralExpression node) => visitExpression(node);
+ @override
T visitVariableDeclarationList(VariableDeclarationList node) =>
visitExpression(node);
+ @override
T visitAssignment(Assignment node) => visitExpression(node);
+ @override
T visitVariableInitialization(VariableInitialization node) =>
visitExpression(node);
+ @override
T visitConditional(Conditional node) => visitExpression(node);
+ @override
T visitNew(New node) => visitExpression(node);
+ @override
T visitCall(Call node) => visitExpression(node);
+ @override
T visitBinary(Binary node) => visitExpression(node);
+ @override
T visitPrefix(Prefix node) => visitExpression(node);
+ @override
T visitPostfix(Postfix node) => visitExpression(node);
+ @override
T visitAccess(PropertyAccess node) => visitExpression(node);
+ @override
T visitVariableUse(VariableUse node) => visitVariableReference(node);
+ @override
T visitVariableDeclaration(VariableDeclaration node) =>
visitVariableReference(node);
+ @override
T visitParameter(Parameter node) => visitVariableDeclaration(node);
+ @override
T visitThis(This node) => visitParameter(node);
+ @override
T visitNamedFunction(NamedFunction node) => visitExpression(node);
T visitFunctionExpression(FunctionExpression node) => visitExpression(node);
+ @override
T visitFun(Fun node) => visitFunctionExpression(node);
+ @override
T visitArrowFunction(ArrowFunction node) => visitFunctionExpression(node);
T visitToken(DeferredToken node) => visitExpression(node);
+ @override
T visitDeferredStatement(DeferredStatement node) => visitStatement(node);
+ @override
T visitDeferredExpression(DeferredExpression node) => visitExpression(node);
+ @override
T visitDeferredNumber(DeferredNumber node) => visitToken(node);
+ @override
T visitDeferredString(DeferredString node) => visitToken(node);
T visitLiteral(Literal node) => visitExpression(node);
+ @override
T visitLiteralBool(LiteralBool node) => visitLiteral(node);
+ @override
T visitLiteralString(LiteralString node) => visitLiteral(node);
+ @override
T visitLiteralNumber(LiteralNumber node) => visitLiteral(node);
+ @override
T visitLiteralNull(LiteralNull node) => visitLiteral(node);
+ @override
T visitStringConcatenation(StringConcatenation node) => visitLiteral(node);
+ @override
T visitName(Name node) => visitNode(node);
+ @override
T visitParentheses(Parentheses node) => visitExpression(node);
+ @override
T visitArrayInitializer(ArrayInitializer node) => visitExpression(node);
+ @override
T visitArrayHole(ArrayHole node) => visitExpression(node);
+ @override
T visitObjectInitializer(ObjectInitializer node) => visitExpression(node);
+ @override
T visitProperty(Property node) => visitNode(node);
+ @override
T visitMethodDefinition(MethodDefinition node) => visitNode(node);
+ @override
T visitRegExpLiteral(RegExpLiteral node) => visitExpression(node);
T visitInterpolatedNode(InterpolatedNode node) => visitNode(node);
+ @override
T visitInterpolatedExpression(InterpolatedExpression node) =>
visitInterpolatedNode(node);
+ @override
T visitInterpolatedLiteral(InterpolatedLiteral node) =>
visitInterpolatedNode(node);
+ @override
T visitInterpolatedParameter(InterpolatedParameter node) =>
visitInterpolatedNode(node);
+ @override
T visitInterpolatedSelector(InterpolatedSelector node) =>
visitInterpolatedNode(node);
+ @override
T visitInterpolatedStatement(InterpolatedStatement node) =>
visitInterpolatedNode(node);
+ @override
T visitInterpolatedDeclaration(InterpolatedDeclaration node) {
return visitInterpolatedNode(node);
}
+ @override
T visitAwait(Await node) => visitExpression(node);
+ @override
T visitDartYield(DartYield node) => visitStatement(node);
}
class BaseVisitorVoid extends BaseVisitor<void> {
+ @override
void visitNode(Node node) {
node.visitChildren(this);
}
// Ignore comments by default.
+ @override
void visitComment(Comment node) {}
}
@@ -289,131 +356,198 @@
const BaseVisitor1();
R visitNode(Node node, A arg);
+ @override
R visitComment(Comment node, A arg);
+ @override
R visitProgram(Program node, A arg) => visitNode(node, arg);
R visitStatement(Statement node, A arg) => visitNode(node, arg);
R visitLoop(Loop node, A arg) => visitStatement(node, arg);
R visitJump(Statement node, A arg) => visitStatement(node, arg);
+ @override
R visitBlock(Block node, A arg) => visitStatement(node, arg);
+ @override
R visitExpressionStatement(ExpressionStatement node, A arg) =>
visitStatement(node, arg);
+ @override
R visitEmptyStatement(EmptyStatement node, A arg) =>
visitStatement(node, arg);
+ @override
R visitIf(If node, A arg) => visitStatement(node, arg);
+ @override
R visitFor(For node, A arg) => visitLoop(node, arg);
+ @override
R visitForIn(ForIn node, A arg) => visitLoop(node, arg);
+ @override
R visitWhile(While node, A arg) => visitLoop(node, arg);
+ @override
R visitDo(Do node, A arg) => visitLoop(node, arg);
+ @override
R visitContinue(Continue node, A arg) => visitJump(node, arg);
+ @override
R visitBreak(Break node, A arg) => visitJump(node, arg);
+ @override
R visitReturn(Return node, A arg) => visitJump(node, arg);
+ @override
R visitThrow(Throw node, A arg) => visitJump(node, arg);
+ @override
R visitTry(Try node, A arg) => visitStatement(node, arg);
+ @override
R visitSwitch(Switch node, A arg) => visitStatement(node, arg);
+ @override
R visitFunctionDeclaration(FunctionDeclaration node, A arg) =>
visitStatement(node, arg);
+ @override
R visitLabeledStatement(LabeledStatement node, A arg) =>
visitStatement(node, arg);
+ @override
R visitLiteralStatement(LiteralStatement node, A arg) =>
visitStatement(node, arg);
+ @override
R visitCatch(Catch node, A arg) => visitNode(node, arg);
+ @override
R visitCase(Case node, A arg) => visitNode(node, arg);
+ @override
R visitDefault(Default node, A arg) => visitNode(node, arg);
R visitExpression(Expression node, A arg) => visitNode(node, arg);
R visitVariableReference(VariableReference node, A arg) =>
visitExpression(node, arg);
+ @override
R visitLiteralExpression(LiteralExpression node, A arg) =>
visitExpression(node, arg);
+ @override
R visitVariableDeclarationList(VariableDeclarationList node, A arg) =>
visitExpression(node, arg);
+ @override
R visitAssignment(Assignment node, A arg) => visitExpression(node, arg);
+ @override
R visitVariableInitialization(VariableInitialization node, A arg) =>
visitExpression(node, arg);
+ @override
R visitConditional(Conditional node, A arg) => visitExpression(node, arg);
+ @override
R visitNew(New node, A arg) => visitExpression(node, arg);
+ @override
R visitCall(Call node, A arg) => visitExpression(node, arg);
+ @override
R visitBinary(Binary node, A arg) => visitExpression(node, arg);
+ @override
R visitPrefix(Prefix node, A arg) => visitExpression(node, arg);
+ @override
R visitPostfix(Postfix node, A arg) => visitExpression(node, arg);
+ @override
R visitAccess(PropertyAccess node, A arg) => visitExpression(node, arg);
+ @override
R visitVariableUse(VariableUse node, A arg) =>
visitVariableReference(node, arg);
+ @override
R visitVariableDeclaration(VariableDeclaration node, A arg) =>
visitVariableReference(node, arg);
+ @override
R visitParameter(Parameter node, A arg) =>
visitVariableDeclaration(node, arg);
+ @override
R visitThis(This node, A arg) => visitParameter(node, arg);
+ @override
R visitNamedFunction(NamedFunction node, A arg) => visitExpression(node, arg);
+ @override
R visitFun(Fun node, A arg) => visitExpression(node, arg);
+ @override
R visitArrowFunction(ArrowFunction node, A arg) => visitExpression(node, arg);
R visitToken(DeferredToken node, A arg) => visitExpression(node, arg);
+ @override
R visitDeferredStatement(DeferredStatement node, A arg) =>
visitStatement(node, arg);
+ @override
R visitDeferredExpression(DeferredExpression node, A arg) =>
visitExpression(node, arg);
+ @override
R visitDeferredNumber(DeferredNumber node, A arg) => visitToken(node, arg);
+ @override
R visitDeferredString(DeferredString node, A arg) => visitToken(node, arg);
R visitLiteral(Literal node, A arg) => visitExpression(node, arg);
+ @override
R visitLiteralBool(LiteralBool node, A arg) => visitLiteral(node, arg);
+ @override
R visitLiteralString(LiteralString node, A arg) => visitLiteral(node, arg);
+ @override
R visitLiteralNumber(LiteralNumber node, A arg) => visitLiteral(node, arg);
+ @override
R visitLiteralNull(LiteralNull node, A arg) => visitLiteral(node, arg);
+ @override
R visitStringConcatenation(StringConcatenation node, A arg) =>
visitLiteral(node, arg);
+ @override
R visitName(Name node, A arg) => visitNode(node, arg);
+ @override
R visitParentheses(Parentheses node, A arg) => visitExpression(node, arg);
+ @override
R visitArrayInitializer(ArrayInitializer node, A arg) =>
visitExpression(node, arg);
+ @override
R visitArrayHole(ArrayHole node, A arg) => visitExpression(node, arg);
+ @override
R visitObjectInitializer(ObjectInitializer node, A arg) =>
visitExpression(node, arg);
+ @override
R visitProperty(Property node, A arg) => visitNode(node, arg);
+ @override
R visitMethodDefinition(MethodDefinition node, A arg) => visitNode(node, arg);
+ @override
R visitRegExpLiteral(RegExpLiteral node, A arg) => visitExpression(node, arg);
R visitInterpolatedNode(InterpolatedNode node, A arg) => visitNode(node, arg);
+ @override
R visitInterpolatedExpression(InterpolatedExpression node, A arg) =>
visitInterpolatedNode(node, arg);
+ @override
R visitInterpolatedLiteral(InterpolatedLiteral node, A arg) =>
visitInterpolatedNode(node, arg);
+ @override
R visitInterpolatedParameter(InterpolatedParameter node, A arg) =>
visitInterpolatedNode(node, arg);
+ @override
R visitInterpolatedSelector(InterpolatedSelector node, A arg) =>
visitInterpolatedNode(node, arg);
+ @override
R visitInterpolatedStatement(InterpolatedStatement node, A arg) =>
visitInterpolatedNode(node, arg);
+ @override
R visitInterpolatedDeclaration(InterpolatedDeclaration node, A arg) {
return visitInterpolatedNode(node, arg);
}
+ @override
R visitAwait(Await node, A arg) => visitExpression(node, arg);
+ @override
R visitDartYield(DartYield node, A arg) => visitStatement(node, arg);
}
class BaseVisitor1Void<A> extends BaseVisitor1<void, A> {
+ @override
void visitNode(Node node, A arg) {
node.visitChildren1(this, arg);
}
// Ignore comments by default.
+ @override
void visitComment(Comment node, A arg) {}
}
@@ -477,38 +611,48 @@
final List<Statement> body;
Program(this.body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitProgram(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitProgram(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Statement statement in body) statement.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Statement statement in body) statement.accept1(visitor, arg);
}
+ @override
Program _clone() => Program(body);
}
abstract class Statement extends Node {
+ @override
Statement toStatement() => this;
}
/// Interface for a deferred [Statement] value. An implementation has to provide
/// a value via the [statement] getter the latest when the ast is printed.
abstract class DeferredStatement extends Statement {
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDeferredStatement(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDeferredStatement(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
statement.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
statement.accept1(visitor, arg);
}
@@ -523,19 +667,24 @@
Block.empty() : this.statements = [];
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitBlock(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitBlock(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Statement statement in statements) statement.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Statement statement in statements) statement.accept1(visitor, arg);
}
+ @override
Block _clone() => Block(statements);
}
@@ -546,34 +695,44 @@
assert(this.expression != null);
}
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitExpressionStatement(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitExpressionStatement(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
expression.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
expression.accept1(visitor, arg);
}
+ @override
ExpressionStatement _clone() => ExpressionStatement(expression);
}
class EmptyStatement extends Statement {
EmptyStatement();
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitEmptyStatement(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitEmptyStatement(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
EmptyStatement _clone() => EmptyStatement();
}
@@ -588,23 +747,28 @@
bool get hasElse => otherwise is! EmptyStatement;
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitIf(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitIf(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
condition.accept(visitor);
then.accept(visitor);
otherwise.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
condition.accept1(visitor, arg);
then.accept1(visitor, arg);
otherwise.accept1(visitor, arg);
}
+ @override
If _clone() => If(condition, then, otherwise);
}
@@ -621,11 +785,14 @@
For(this.init, this.condition, this.update, Statement body) : super(body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitFor(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitFor(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
if (init != null) init.accept(visitor);
if (condition != null) condition.accept(visitor);
@@ -633,6 +800,7 @@
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
if (init != null) init.accept1(visitor, arg);
if (condition != null) condition.accept1(visitor, arg);
@@ -640,6 +808,7 @@
body.accept1(visitor, arg);
}
+ @override
For _clone() => For(init, condition, update, body);
}
@@ -651,23 +820,28 @@
ForIn(this.leftHandSide, this.object, Statement body) : super(body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitForIn(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitForIn(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
leftHandSide.accept(visitor);
object.accept(visitor);
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
leftHandSide.accept1(visitor, arg);
object.accept1(visitor, arg);
body.accept1(visitor, arg);
}
+ @override
ForIn _clone() => ForIn(leftHandSide, object, body);
}
@@ -676,21 +850,26 @@
While(this.condition, Statement body) : super(body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitWhile(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitWhile(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
condition.accept(visitor);
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
condition.accept1(visitor, arg);
body.accept1(visitor, arg);
}
+ @override
While _clone() => While(condition, body);
}
@@ -699,21 +878,26 @@
Do(Statement body, this.condition) : super(body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDo(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDo(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
body.accept(visitor);
condition.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
body.accept1(visitor, arg);
condition.accept1(visitor, arg);
}
+ @override
Do _clone() => Do(body, condition);
}
@@ -722,15 +906,20 @@
Continue(this.targetLabel);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitContinue(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitContinue(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
Continue _clone() => Continue(targetLabel);
}
@@ -739,15 +928,20 @@
Break(this.targetLabel);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitBreak(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitBreak(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
Break _clone() => Break(targetLabel);
}
@@ -756,19 +950,24 @@
Return([this.value = null]);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitReturn(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitReturn(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
if (value != null) value.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
if (value != null) value.accept1(visitor, arg);
}
+ @override
Return _clone() => Return(value);
}
@@ -777,19 +976,24 @@
Throw(this.expression);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitThrow(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitThrow(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
expression.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
expression.accept1(visitor, arg);
}
+ @override
Throw _clone() => Throw(expression);
}
@@ -802,23 +1006,28 @@
assert(catchPart != null || finallyPart != null);
}
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitTry(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitTry(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
body.accept(visitor);
if (catchPart != null) catchPart.accept(visitor);
if (finallyPart != null) finallyPart.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
body.accept1(visitor, arg);
if (catchPart != null) catchPart.accept1(visitor, arg);
if (finallyPart != null) finallyPart.accept1(visitor, arg);
}
+ @override
Try _clone() => Try(body, catchPart, finallyPart);
}
@@ -828,21 +1037,26 @@
Catch(this.declaration, this.body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitCatch(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitCatch(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
declaration.accept(visitor);
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
declaration.accept1(visitor, arg);
body.accept1(visitor, arg);
}
+ @override
Catch _clone() => Catch(declaration, body);
}
@@ -852,21 +1066,26 @@
Switch(this.key, this.cases);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitSwitch(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitSwitch(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
key.accept(visitor);
for (SwitchClause clause in cases) clause.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
key.accept1(visitor, arg);
for (SwitchClause clause in cases) clause.accept1(visitor, arg);
}
+ @override
Switch _clone() => Switch(key, cases);
}
@@ -881,40 +1100,50 @@
Case(this.expression, Block body) : super(body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitCase(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitCase(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
expression.accept(visitor);
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
expression.accept1(visitor, arg);
body.accept1(visitor, arg);
}
+ @override
Case _clone() => Case(expression, body);
}
class Default extends SwitchClause {
Default(Block body) : super(body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDefault(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDefault(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
body.accept1(visitor, arg);
}
+ @override
Default _clone() => Default(body);
}
@@ -924,21 +1153,26 @@
FunctionDeclaration(this.name, this.function);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitFunctionDeclaration(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitFunctionDeclaration(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
name.accept(visitor);
function.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
name.accept1(visitor, arg);
function.accept1(visitor, arg);
}
+ @override
FunctionDeclaration _clone() => FunctionDeclaration(name, function);
}
@@ -948,19 +1182,24 @@
LabeledStatement(this.label, this.body);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLabeledStatement(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLabeledStatement(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
body.accept1(visitor, arg);
}
+ @override
LabeledStatement _clone() => LabeledStatement(label, body);
}
@@ -969,15 +1208,20 @@
LiteralStatement(this.code);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralStatement(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLiteralStatement(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
LiteralStatement _clone() => LiteralStatement(code);
}
@@ -990,19 +1234,24 @@
DartYield(this.expression, this.hasStar);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDartYield(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDartYield(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
expression.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
expression.accept1(visitor, arg);
}
+ @override
DartYield _clone() => DartYield(expression, hasStar);
}
@@ -1011,6 +1260,7 @@
// have precedence depending on how the deferred node is resolved.
int get precedenceLevel;
+ @override
Statement toStatement() => ExpressionStatement(this);
}
@@ -1025,17 +1275,21 @@
// that is used. How should the printer know if an occurrence of a Name is meant
// to be a Literal or a Declaration (which includes a VariableUse)?
abstract class Name extends Literal implements Declaration, Parameter {
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitName(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitName(this, arg);
+ @override
Name _clone();
/// Returns the text of this name.
///
/// May throw if the text has not been decided. Typically the text is decided
/// in some finalization phase that happens before the AST is printed.
+ @override
String get name;
/// Returns a unique [key] for this name.
@@ -1044,6 +1298,7 @@
/// consumption. As such, it might be long or cryptic.
String get key;
+ @override
bool get allowRename => false;
}
@@ -1060,10 +1315,12 @@
@override
String get value => name.name;
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
name.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
name.accept1(visitor, arg);
}
@@ -1073,19 +1330,25 @@
final String template;
LiteralExpression(this.template);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralExpression(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLiteralExpression(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
LiteralExpression _clone() => LiteralExpression(template);
// Code that uses LiteralExpression must take care of operator precedences,
// and put parenthesis if needed.
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -1101,26 +1364,32 @@
VariableDeclarationList(this.declarations, {this.indentSplits = true});
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitVariableDeclarationList(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitVariableDeclarationList(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (VariableInitialization declaration in declarations) {
declaration.accept(visitor);
}
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (VariableInitialization declaration in declarations) {
declaration.accept1(visitor, arg);
}
}
+ @override
VariableDeclarationList _clone() => VariableDeclarationList(declarations);
+ @override
int get precedenceLevel => EXPRESSION;
}
@@ -1131,21 +1400,27 @@
Parentheses(this.enclosed);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitParentheses(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitParentheses(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
enclosed.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
enclosed.accept1(visitor, arg);
}
+ @override
Parentheses _clone() => Parentheses(enclosed);
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -1160,25 +1435,31 @@
Assignment.compound(this.leftHandSide, this.op, this.value)
: assert(value != null);
+ @override
int get precedenceLevel => ASSIGNMENT;
bool get isCompound => op != null;
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitAssignment(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitAssignment(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
leftHandSide.accept(visitor);
value.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
leftHandSide.accept1(visitor, arg);
value.accept1(visitor, arg);
}
+ @override
Assignment _clone() => Assignment.compound(leftHandSide, op, value);
}
@@ -1190,24 +1471,30 @@
VariableInitialization(this.declaration, this.value);
+ @override
int get precedenceLevel => ASSIGNMENT;
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitVariableInitialization(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitVariableInitialization(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
declaration.accept(visitor);
value?.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
declaration.accept1(visitor, arg);
value?.accept1(visitor, arg);
}
+ @override
VariableInitialization _clone() => VariableInitialization(declaration, value);
}
@@ -1218,25 +1505,31 @@
Conditional(this.condition, this.then, this.otherwise);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitConditional(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitConditional(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
condition.accept(visitor);
then.accept(visitor);
otherwise.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
condition.accept1(visitor, arg);
then.accept1(visitor, arg);
otherwise.accept1(visitor, arg);
}
+ @override
Conditional _clone() => Conditional(condition, then, otherwise);
+ @override
int get precedenceLevel => ASSIGNMENT;
}
@@ -1249,11 +1542,14 @@
this._sourceInformation = sourceInformation;
}
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitCall(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitCall(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
target.accept(visitor);
for (Expression arg in arguments) {
@@ -1261,6 +1557,7 @@
}
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
target.accept1(visitor, arg);
for (Expression arg in arguments) {
@@ -1268,19 +1565,24 @@
}
}
+ @override
Call _clone() => Call(target, arguments);
+ @override
int get precedenceLevel => CALL;
}
class New extends Call {
New(Expression cls, List<Expression> arguments) : super(cls, arguments);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitNew(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitNew(this, arg);
+ @override
New _clone() => New(target, arguments);
}
@@ -1291,25 +1593,32 @@
Binary(this.op, this.left, this.right);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitBinary(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitBinary(this, arg);
+ @override
Binary _clone() => Binary(op, left, right);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
left.accept(visitor);
right.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
left.accept1(visitor, arg);
right.accept1(visitor, arg);
}
+ @override
bool get isCommaOperator => op == ',';
+ @override
int get precedenceLevel {
// TODO(floitsch): switch to constant map.
switch (op) {
@@ -1360,21 +1669,27 @@
Prefix(this.op, this.argument);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitPrefix(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitPrefix(this, arg);
+ @override
Prefix _clone() => Prefix(op, argument);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
argument.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
argument.accept1(visitor, arg);
}
+ @override
int get precedenceLevel => UNARY;
}
@@ -1384,21 +1699,27 @@
Postfix(this.op, this.argument);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitPostfix(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitPostfix(this, arg);
+ @override
Postfix _clone() => Postfix(op, argument);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
argument.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
argument.accept1(visitor, arg);
}
+ @override
int get precedenceLevel => UNARY;
}
@@ -1411,25 +1732,33 @@
assert(_identifierRE.hasMatch(name), "Non-identifier name '$name'");
}
+ @override
T accept<T>(NodeVisitor<T> visitor);
+ @override
int get precedenceLevel => PRIMARY;
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
}
class VariableUse extends VariableReference {
VariableUse(String name) : super(name);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitVariableUse(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitVariableUse(this, arg);
+ @override
VariableUse _clone() => VariableUse(name);
+ @override
String toString() => 'VariableUse($name)';
}
@@ -1438,33 +1767,42 @@
VariableDeclaration(String name, {this.allowRename = true}) : super(name);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitVariableDeclaration(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitVariableDeclaration(this, arg);
+ @override
VariableDeclaration _clone() => VariableDeclaration(name);
}
class Parameter extends VariableDeclaration {
Parameter(String name) : super(name);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitParameter(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitParameter(this, arg);
+ @override
Parameter _clone() => Parameter(name);
}
class This extends Parameter {
This() : super("this");
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitThis(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitThis(this, arg);
+ @override
This _clone() => This();
}
@@ -1474,23 +1812,29 @@
NamedFunction(this.name, this.function);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitNamedFunction(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitNamedFunction(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
name.accept(visitor);
function.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
name.accept1(visitor, arg);
function.accept1(visitor, arg);
}
+ @override
NamedFunction _clone() => NamedFunction(name, function);
+ @override
int get precedenceLevel => LEFT_HAND_SIDE;
}
@@ -1510,23 +1854,29 @@
Fun(this.params, this.body, {this.asyncModifier = AsyncModifier.sync});
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitFun(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitFun(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Parameter param in params) param.accept(visitor);
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Parameter param in params) param.accept1(visitor, arg);
body.accept1(visitor, arg);
}
+ @override
Fun _clone() => Fun(params, body, asyncModifier: asyncModifier);
+ @override
int get precedenceLevel => LEFT_HAND_SIDE;
}
@@ -1546,25 +1896,31 @@
{this.asyncModifier = AsyncModifier.sync,
this.implicitReturnAllowed = true});
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrowFunction(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitArrowFunction(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Parameter param in params) param.accept(visitor);
body.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Parameter param in params) param.accept1(visitor, arg);
body.accept1(visitor, arg);
}
+ @override
ArrowFunction _clone() => ArrowFunction(params, body,
asyncModifier: asyncModifier,
implicitReturnAllowed: implicitReturnAllowed);
+ @override
int get precedenceLevel => ASSIGNMENT;
}
@@ -1588,6 +1944,7 @@
static const List<AsyncModifier> values = [sync, async, asyncStar, syncStar];
+ @override
String toString() => description;
}
@@ -1603,23 +1960,29 @@
PropertyAccess.indexed(this.receiver, int index)
: selector = LiteralNumber('$index');
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitAccess(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitAccess(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
receiver.accept(visitor);
selector.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
receiver.accept1(visitor, arg);
selector.accept1(visitor, arg);
}
+ @override
PropertyAccess _clone() => PropertyAccess(receiver, selector);
+ @override
int get precedenceLevel => LEFT_HAND_SIDE;
}
@@ -1628,36 +1991,45 @@
/// [DeferredToken] is not limited to templates but may also occur in
/// fully instantiated asts.
abstract class DeferredToken extends Expression {
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
DeferredToken _clone() => this;
}
/// Interface for a deferred integer value. An implementation has to provide
/// a value via the [value] getter the latest when the ast is printed.
abstract class DeferredNumber extends DeferredToken implements Literal {
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDeferredNumber(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDeferredNumber(this, arg);
int get value;
+ @override
int get precedenceLevel => value.isNegative ? UNARY : PRIMARY;
}
/// Interface for a deferred string value. An implementation has to provide
/// a value via the [value] getter the latest when the ast is printed.
abstract class DeferredString extends DeferredToken implements Literal {
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDeferredString(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDeferredString(this, arg);
String get value;
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -1666,8 +2038,10 @@
/// Also, [precedenceLevel] has to return the same value that
/// [value.precedenceLevel] returns once [value] is bound to an [Expression].
abstract class DeferredExpression extends DeferredToken {
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitDeferredExpression(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitDeferredExpression(this, arg);
@@ -1675,10 +2049,13 @@
}
abstract class Literal extends Expression {
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -1687,24 +2064,30 @@
LiteralBool(this.value);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralBool(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLiteralBool(this, arg);
// [visitChildren] inherited from [Literal].
+ @override
LiteralBool _clone() => LiteralBool(value);
}
class LiteralNull extends Literal {
LiteralNull();
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralNull(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLiteralNull(this, arg);
+ @override
LiteralNull _clone() => LiteralNull();
}
@@ -1718,11 +2101,14 @@
/// printer's settings.
LiteralString(this.value);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralString(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLiteralString(this, arg);
+ @override
LiteralString _clone() => LiteralString(value);
@override
@@ -1758,19 +2144,24 @@
/// concatenated string.
StringConcatenation(this.parts);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitStringConcatenation(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitStringConcatenation(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Literal part in parts) part.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Literal part in parts) part.accept1(visitor, arg);
}
+ @override
StringConcatenation _clone() => StringConcatenation(this.parts);
}
@@ -1779,13 +2170,17 @@
LiteralNumber(this.value);
+ @override
int get precedenceLevel => value.startsWith('-') ? UNARY : PRIMARY;
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitLiteralNumber(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitLiteralNumber(this, arg);
+ @override
LiteralNumber _clone() => LiteralNumber(value);
}
@@ -1794,38 +2189,50 @@
ArrayInitializer(this.elements) : assert(!elements.contains(null));
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayInitializer(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitArrayInitializer(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Expression element in elements) element.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Expression element in elements) element.accept1(visitor, arg);
}
+ @override
ArrayInitializer _clone() => ArrayInitializer(elements);
+ @override
int get precedenceLevel => PRIMARY;
}
/// An empty place in an [ArrayInitializer].
/// For example the list [1, , , 2] would contain two holes.
class ArrayHole extends Expression {
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayHole(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitArrayHole(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
ArrayHole _clone() => ArrayHole();
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -1840,22 +2247,28 @@
/// If false print each property on a seperate line.
ObjectInitializer(this.properties, {this.isOneLiner = true});
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitObjectInitializer(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitObjectInitializer(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
for (Property init in properties) init.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
for (Property init in properties) init.accept1(visitor, arg);
}
+ @override
ObjectInitializer _clone() =>
ObjectInitializer(properties, isOneLiner: isOneLiner);
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -1866,21 +2279,26 @@
Property(this.name, this.value)
: assert(name is Literal || name is DeferredExpression);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitProperty(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitProperty(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {
name.accept(visitor);
value.accept(visitor);
}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
name.accept1(visitor, arg);
value.accept1(visitor, arg);
}
+ @override
Property _clone() => Property(name, value);
}
@@ -1897,6 +2315,7 @@
@override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitMethodDefinition(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitMethodDefinition(this, arg);
@@ -1926,125 +2345,166 @@
}
class InterpolatedExpression extends Expression with InterpolatedNode {
+ @override
final nameOrPosition;
InterpolatedExpression(this.nameOrPosition);
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitInterpolatedExpression(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitInterpolatedExpression(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
InterpolatedExpression _clone() => InterpolatedExpression(nameOrPosition);
+ @override
int get precedenceLevel => PRIMARY;
}
class InterpolatedLiteral extends Literal with InterpolatedNode {
+ @override
final nameOrPosition;
InterpolatedLiteral(this.nameOrPosition);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitInterpolatedLiteral(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitInterpolatedLiteral(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
InterpolatedLiteral _clone() => InterpolatedLiteral(nameOrPosition);
}
class InterpolatedParameter extends Expression
with InterpolatedNode
implements Parameter {
+ @override
final nameOrPosition;
InterpolatedParameter(this.nameOrPosition);
+ @override
String get name {
throw "InterpolatedParameter.name must not be invoked";
}
+ @override
bool get allowRename => false;
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitInterpolatedParameter(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitInterpolatedParameter(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
InterpolatedParameter _clone() => InterpolatedParameter(nameOrPosition);
+ @override
int get precedenceLevel => PRIMARY;
}
class InterpolatedSelector extends Expression with InterpolatedNode {
+ @override
final nameOrPosition;
InterpolatedSelector(this.nameOrPosition);
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitInterpolatedSelector(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitInterpolatedSelector(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
InterpolatedSelector _clone() => InterpolatedSelector(nameOrPosition);
+ @override
int get precedenceLevel => PRIMARY;
}
class InterpolatedStatement extends Statement with InterpolatedNode {
+ @override
final nameOrPosition;
InterpolatedStatement(this.nameOrPosition);
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitInterpolatedStatement(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitInterpolatedStatement(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
InterpolatedStatement _clone() => InterpolatedStatement(nameOrPosition);
}
class InterpolatedDeclaration extends Expression
with InterpolatedNode
implements Declaration {
+ @override
final nameOrPosition;
InterpolatedDeclaration(this.nameOrPosition);
+ @override
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitInterpolatedDeclaration(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitInterpolatedDeclaration(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
InterpolatedDeclaration _clone() {
return InterpolatedDeclaration(nameOrPosition);
}
@@ -2065,17 +2525,23 @@
RegExpLiteral(this.pattern);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitRegExpLiteral(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitRegExpLiteral(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
+ @override
RegExpLiteral _clone() => RegExpLiteral(pattern);
+ @override
int get precedenceLevel => PRIMARY;
}
@@ -2089,18 +2555,24 @@
Await(this.expression);
+ @override
int get precedenceLevel => UNARY;
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitAwait(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitAwait(this, arg);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) => expression.accept(visitor);
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
expression.accept1(visitor, arg);
+ @override
Await _clone() => Await(expression);
}
@@ -2113,15 +2585,20 @@
Comment(this.comment);
+ @override
T accept<T>(NodeVisitor<T> visitor) => visitor.visitComment(this);
+ @override
R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
visitor.visitComment(this, arg);
+ @override
Comment _clone() => Comment(comment);
+ @override
void visitChildren<T>(NodeVisitor<T> visitor) {}
+ @override
void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {}
}
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 562107f..6234daf 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -55,6 +55,7 @@
class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext {
final StringBuffer buffer = StringBuffer();
+ @override
void emit(String string) {
buffer.write(string);
}
@@ -63,6 +64,7 @@
}
class _DebugJavaScriptPrintingContext extends SimpleJavaScriptPrintingContext {
+ @override
bool get isDebugContext => true;
}
@@ -1589,31 +1591,38 @@
}
}
+ @override
void visitFunctionDeclaration(FunctionDeclaration declaration) {
// Note that we don't bother collecting the name of the function.
collectVarsInFunction(declaration.function);
}
+ @override
void visitNamedFunction(NamedFunction namedFunction) {
// Note that we don't bother collecting the name of the function.
collectVarsInFunction(namedFunction.function);
}
+ @override
void visitMethodDefinition(MethodDefinition method) {
// Note that we don't bother collecting the name of the function.
collectVarsInFunction(method.function);
}
+ @override
void visitFun(Fun fun) {
collectVarsInFunction(fun);
}
+ @override
void visitArrowFunction(ArrowFunction fun) {
collectVarsInFunction(fun);
}
+ @override
void visitThis(This node) {}
+ @override
void visitComment(Comment node) {
if (node.comment.contains(disableVariableMinificationPattern)) {
enableRenaming = false;
@@ -1622,6 +1631,7 @@
}
}
+ @override
void visitVariableDeclaration(VariableDeclaration decl) {
if (enableRenaming && decl.allowRename) vars.add(decl.name);
}
@@ -1634,35 +1644,52 @@
DanglingElseVisitor(this.context);
+ @override
bool visitProgram(Program node) => false;
+ @override
bool visitNode(Node node) {
context.error("Forgot node: $node");
return true;
}
+ @override
bool visitComment(Comment node) => true;
+ @override
bool visitBlock(Block node) => false;
+ @override
bool visitExpressionStatement(ExpressionStatement node) => false;
+ @override
bool visitEmptyStatement(EmptyStatement node) => false;
+ @override
bool visitDeferredStatement(DeferredStatement node) {
return node.statement.accept(this);
}
+ @override
bool visitIf(If node) {
if (!node.hasElse) return true;
return node.otherwise.accept(this);
}
+ @override
bool visitFor(For node) => node.body.accept(this);
+ @override
bool visitForIn(ForIn node) => node.body.accept(this);
+ @override
bool visitWhile(While node) => node.body.accept(this);
+ @override
bool visitDo(Do node) => false;
+ @override
bool visitContinue(Continue node) => false;
+ @override
bool visitBreak(Break node) => false;
+ @override
bool visitReturn(Return node) => false;
+ @override
bool visitThrow(Throw node) => false;
+ @override
bool visitTry(Try node) {
if (node.finallyPart != null) {
return node.finallyPart.accept(this);
@@ -1671,16 +1698,25 @@
}
}
+ @override
bool visitCatch(Catch node) => node.body.accept(this);
+ @override
bool visitSwitch(Switch node) => false;
+ @override
bool visitCase(Case node) => false;
+ @override
bool visitDefault(Default node) => false;
+ @override
bool visitFunctionDeclaration(FunctionDeclaration node) => false;
+ @override
bool visitLabeledStatement(LabeledStatement node) => node.body.accept(this);
+ @override
bool visitLiteralStatement(LiteralStatement node) => true;
+ @override
bool visitDartYield(DartYield node) => false;
+ @override
bool visitExpression(Expression node) => false;
}
@@ -1693,10 +1729,15 @@
}
class IdentityNamer implements LocalNamer {
+ @override
String getName(String oldName) => oldName;
+ @override
String declareVariable(String oldName) => oldName;
+ @override
String declareParameter(String oldName) => oldName;
+ @override
void enterScope(VarCollector vars) {}
+ @override
void leaveScope() {}
}
@@ -1709,6 +1750,7 @@
MinifyRenamer();
+ @override
void enterScope(VarCollector vars) {
maps.add({});
variableNumberStack.add(variableNumber);
@@ -1717,12 +1759,14 @@
vars.forEachParam(declareParameter);
}
+ @override
void leaveScope() {
maps.removeLast();
variableNumber = variableNumberStack.removeLast();
parameterNumber = parameterNumberStack.removeLast();
}
+ @override
String getName(String oldName) {
// Go from inner scope to outer looking for mapping of name.
for (int i = maps.length - 1; i >= 0; i--) {
@@ -1750,6 +1794,7 @@
// that we give up trying to be nice to the compression algorithm and just
// use the same namespace for arguments and variables, starting with A, and
// moving on to a0, a1, etc.
+ @override
String declareVariable(String oldName) {
if (avoidRenaming(oldName)) return oldName;
var newName;
@@ -1764,6 +1809,7 @@
return newName;
}
+ @override
String declareParameter(String oldName) {
if (avoidRenaming(oldName)) return oldName;
var newName;
diff --git a/pkg/js_ast/lib/src/template.dart b/pkg/js_ast/lib/src/template.dart
index bdcf3c0..de78364 100644
--- a/pkg/js_ast/lib/src/template.dart
+++ b/pkg/js_ast/lib/src/template.dart
@@ -185,6 +185,7 @@
return VariableDeclaration(value);
}
+ @override
Instantiator visitInterpolatedExpression(InterpolatedExpression node) {
var nameOrPosition = node.nameOrPosition;
return (arguments) {
@@ -196,6 +197,7 @@
};
}
+ @override
Instantiator visitInterpolatedDeclaration(InterpolatedDeclaration node) {
var nameOrPosition = node.nameOrPosition;
return (arguments) {
@@ -226,6 +228,7 @@
return visit(node);
}
+ @override
Instantiator visitInterpolatedLiteral(InterpolatedLiteral node) {
var nameOrPosition = node.nameOrPosition;
return (arguments) {
@@ -235,6 +238,7 @@
};
}
+ @override
Instantiator visitInterpolatedParameter(InterpolatedParameter node) {
var nameOrPosition = node.nameOrPosition;
return (arguments) {
@@ -252,6 +256,7 @@
};
}
+ @override
Instantiator visitInterpolatedSelector(InterpolatedSelector node) {
// A selector is an expression, as in `a[selector]`.
// A String argument converted into a LiteralString, so `a.#` with argument
@@ -266,6 +271,7 @@
};
}
+ @override
Instantiator visitInterpolatedStatement(InterpolatedStatement node) {
var nameOrPosition = node.nameOrPosition;
return (arguments) {
@@ -295,6 +301,7 @@
return visit(node);
}
+ @override
Instantiator visitProgram(Program node) {
List<Instantiator> instantiators =
node.body.map(visitSplayableStatement).toList();
@@ -316,6 +323,7 @@
};
}
+ @override
Instantiator visitBlock(Block node) {
List<Instantiator> instantiators =
node.statements.map(visitSplayableStatement).toList();
@@ -339,6 +347,7 @@
};
}
+ @override
Instantiator visitExpressionStatement(ExpressionStatement node) {
Instantiator buildExpression = visit(node.expression);
return (arguments) {
@@ -346,9 +355,11 @@
};
}
+ @override
Instantiator visitEmptyStatement(EmptyStatement node) =>
(arguments) => EmptyStatement();
+ @override
Instantiator visitIf(If node) {
if (node.condition is InterpolatedExpression) {
return visitIfConditionalCompilation(node);
@@ -397,6 +408,7 @@
};
}
+ @override
Instantiator visitFor(For node) {
Instantiator makeInit = visitNullable(node.init);
Instantiator makeCondition = visitNullable(node.condition);
@@ -408,6 +420,7 @@
};
}
+ @override
Instantiator visitForIn(ForIn node) {
Instantiator makeLeftHandSide = visit(node.leftHandSide);
Instantiator makeObject = visit(node.object);
@@ -422,6 +435,7 @@
throw UnimplementedError('$this.$name');
}
+ @override
Instantiator visitWhile(While node) {
Instantiator makeCondition = visit(node.condition);
Instantiator makeBody = visit(node.body);
@@ -430,6 +444,7 @@
};
}
+ @override
Instantiator visitDo(Do node) {
Instantiator makeBody = visit(node.body);
Instantiator makeCondition = visit(node.condition);
@@ -438,26 +453,32 @@
};
}
+ @override
Instantiator visitContinue(Continue node) =>
(arguments) => Continue(node.targetLabel);
+ @override
Instantiator visitBreak(Break node) => (arguments) => Break(node.targetLabel);
+ @override
Instantiator visitReturn(Return node) {
Instantiator makeExpression = visitNullable(node.value);
return (arguments) => Return(makeExpression(arguments));
}
+ @override
Instantiator visitDartYield(DartYield node) {
Instantiator makeExpression = visit(node.expression);
return (arguments) => DartYield(makeExpression(arguments), node.hasStar);
}
+ @override
Instantiator visitThrow(Throw node) {
Instantiator makeExpression = visit(node.expression);
return (arguments) => Throw(makeExpression(arguments));
}
+ @override
Instantiator visitTry(Try node) {
Instantiator makeBody = visit(node.body);
Instantiator makeCatch = visitNullable(node.catchPart);
@@ -466,6 +487,7 @@
Try(makeBody(arguments), makeCatch(arguments), makeFinally(arguments));
}
+ @override
Instantiator visitCatch(Catch node) {
Instantiator makeDeclaration = visit(node.declaration);
Instantiator makeBody = visit(node.body);
@@ -473,6 +495,7 @@
Catch(makeDeclaration(arguments), makeBody(arguments));
}
+ @override
Instantiator visitSwitch(Switch node) {
Instantiator makeKey = visit(node.key);
Iterable<Instantiator> makeCases = node.cases.map(visit);
@@ -485,6 +508,7 @@
};
}
+ @override
Instantiator visitCase(Case node) {
Instantiator makeExpression = visit(node.expression);
Instantiator makeBody = visit(node.body);
@@ -493,6 +517,7 @@
};
}
+ @override
Instantiator visitDefault(Default node) {
Instantiator makeBody = visit(node.body);
return (arguments) {
@@ -500,6 +525,7 @@
};
}
+ @override
Instantiator visitFunctionDeclaration(FunctionDeclaration node) {
Instantiator makeName = visit(node.name);
Instantiator makeFunction = visit(node.function);
@@ -507,16 +533,20 @@
FunctionDeclaration(makeName(arguments), makeFunction(arguments));
}
+ @override
Instantiator visitLabeledStatement(LabeledStatement node) {
Instantiator makeBody = visit(node.body);
return (arguments) => LabeledStatement(node.label, makeBody(arguments));
}
+ @override
Instantiator visitLiteralStatement(LiteralStatement node) =>
TODO('visitLiteralStatement');
+ @override
Instantiator visitLiteralExpression(LiteralExpression node) =>
TODO('visitLiteralExpression');
+ @override
Instantiator visitVariableDeclarationList(VariableDeclarationList node) {
List<Instantiator> declarationMakers =
node.declarations.map(visit).toList();
@@ -530,6 +560,7 @@
};
}
+ @override
Instantiator visitAssignment(Assignment node) {
Instantiator makeLeftHandSide = visit(node.leftHandSide);
String op = node.op;
@@ -540,6 +571,7 @@
};
}
+ @override
Instantiator visitVariableInitialization(VariableInitialization node) {
Instantiator makeDeclaration = visit(node.declaration);
Instantiator makeValue = visitNullable(node.value);
@@ -549,6 +581,7 @@
};
}
+ @override
Instantiator visitConditional(Conditional cond) {
Instantiator makeCondition = visit(cond.condition);
Instantiator makeThen = visit(cond.then);
@@ -557,9 +590,11 @@
makeThen(arguments), makeOtherwise(arguments));
}
+ @override
Instantiator visitNew(New node) =>
handleCallOrNew(node, (target, arguments) => New(target, arguments));
+ @override
Instantiator visitCall(Call node) =>
handleCallOrNew(node, (target, arguments) => Call(target, arguments));
@@ -585,6 +620,7 @@
};
}
+ @override
Instantiator visitBinary(Binary node) {
Instantiator makeLeft = visit(node.left);
Instantiator makeRight = visit(node.right);
@@ -592,29 +628,36 @@
return (arguments) => Binary(op, makeLeft(arguments), makeRight(arguments));
}
+ @override
Instantiator visitPrefix(Prefix node) {
Instantiator makeOperand = visit(node.argument);
String op = node.op;
return (arguments) => Prefix(op, makeOperand(arguments));
}
+ @override
Instantiator visitPostfix(Postfix node) {
Instantiator makeOperand = visit(node.argument);
String op = node.op;
return (arguments) => Postfix(op, makeOperand(arguments));
}
+ @override
Instantiator visitVariableUse(VariableUse node) =>
(arguments) => VariableUse(node.name);
+ @override
Instantiator visitThis(This node) => (arguments) => This();
+ @override
Instantiator visitVariableDeclaration(VariableDeclaration node) =>
(arguments) => VariableDeclaration(node.name);
+ @override
Instantiator visitParameter(Parameter node) =>
(arguments) => Parameter(node.name);
+ @override
Instantiator visitAccess(PropertyAccess node) {
Instantiator makeReceiver = visit(node.receiver);
Instantiator makeSelector = visit(node.selector);
@@ -622,6 +665,7 @@
PropertyAccess(makeReceiver(arguments), makeSelector(arguments));
}
+ @override
Instantiator visitNamedFunction(NamedFunction node) {
Instantiator makeDeclaration = visit(node.name);
Instantiator makeFunction = visit(node.function);
@@ -629,6 +673,7 @@
NamedFunction(makeDeclaration(arguments), makeFunction(arguments));
}
+ @override
Instantiator visitFun(Fun node) {
List<Instantiator> paramMakers = node.params.map(visitSplayable).toList();
Instantiator makeBody = visit(node.body);
@@ -648,6 +693,7 @@
};
}
+ @override
Instantiator visitArrowFunction(ArrowFunction node) {
List<Instantiator> paramMakers = node.params.map(visitSplayable).toList();
Instantiator makeBody = visit(node.body);
@@ -668,26 +714,35 @@
};
}
+ @override
Instantiator visitDeferredExpression(DeferredExpression node) => same(node);
+ @override
Instantiator visitDeferredStatement(DeferredStatement node) => same(node);
+ @override
Instantiator visitDeferredNumber(DeferredNumber node) => same(node);
+ @override
Instantiator visitDeferredString(DeferredString node) => (arguments) => node;
+ @override
Instantiator visitLiteralBool(LiteralBool node) =>
(arguments) => LiteralBool(node.value);
+ @override
Instantiator visitLiteralString(LiteralString node) =>
(arguments) => LiteralString(node.value);
+ @override
Instantiator visitLiteralNumber(LiteralNumber node) =>
(arguments) => LiteralNumber(node.value);
+ @override
Instantiator visitLiteralNull(LiteralNull node) =>
(arguments) => LiteralNull();
+ @override
Instantiator visitStringConcatenation(StringConcatenation node) {
List<Instantiator> partMakers =
node.parts.map(visit).toList(growable: false);
@@ -699,8 +754,10 @@
};
}
+ @override
Instantiator visitName(Name node) => same(node);
+ @override
Instantiator visitParentheses(Parentheses node) {
Instantiator makeEnclosed = visit(node.enclosed);
return (arguments) {
@@ -709,6 +766,7 @@
};
}
+ @override
Instantiator visitArrayInitializer(ArrayInitializer node) {
// TODO(sra): Implement splicing?
List<Instantiator> elementMakers =
@@ -722,10 +780,12 @@
};
}
+ @override
Instantiator visitArrayHole(ArrayHole node) {
return (arguments) => ArrayHole();
}
+ @override
Instantiator visitObjectInitializer(ObjectInitializer node) {
List<Instantiator> propertyMakers =
node.properties.map(visitSplayable).toList();
@@ -744,6 +804,7 @@
};
}
+ @override
Instantiator visitProperty(Property node) {
Instantiator makeName = visit(node.name);
Instantiator makeValue = visit(node.value);
@@ -752,6 +813,7 @@
};
}
+ @override
Instantiator visitMethodDefinition(MethodDefinition node) {
Instantiator makeName = visit(node.name);
Instantiator makeFunction = visit(node.function);
@@ -760,11 +822,14 @@
};
}
+ @override
Instantiator visitRegExpLiteral(RegExpLiteral node) =>
(arguments) => RegExpLiteral(node.pattern);
+ @override
Instantiator visitComment(Comment node) => TODO('visitComment');
+ @override
Instantiator visitAwait(Await node) {
Instantiator makeExpression = visit(node.expression);
return (arguments) {
@@ -789,12 +854,14 @@
node.accept(this);
}
+ @override
void visitNode(Node node) {
int before = count;
node.visitChildren(this);
if (count != before) containsInterpolatedNode.add(node);
}
+ @override
visitInterpolatedNode(InterpolatedNode node) {
containsInterpolatedNode.add(node);
if (node.isNamed) holeNames.add(node.nameOrPosition);
diff --git a/pkg/js_ast/test/deferred_expression_test.dart b/pkg/js_ast/test/deferred_expression_test.dart
index 29fc4d1..ecdb774 100644
--- a/pkg/js_ast/test/deferred_expression_test.dart
+++ b/pkg/js_ast/test/deferred_expression_test.dart
@@ -112,6 +112,7 @@
}
class _DeferredExpression extends DeferredExpression {
+ @override
final Expression value;
_DeferredExpression(this.value);
@@ -162,11 +163,13 @@
_Position(this.startPosition, this.endPosition, this.closingPosition);
+ @override
int get hashCode =>
13 * startPosition.hashCode +
17 * endPosition.hashCode +
19 * closingPosition.hashCode;
+ @override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is _Position &&
@@ -175,6 +178,7 @@
closingPosition == other.closingPosition;
}
+ @override
String toString() {
return '_Position(start=$startPosition,'
'end=$endPosition,closing=$closingPosition)';
diff --git a/pkg/js_ast/test/deferred_statement_test.dart b/pkg/js_ast/test/deferred_statement_test.dart
index 9628cdf..0d309ae 100644
--- a/pkg/js_ast/test/deferred_statement_test.dart
+++ b/pkg/js_ast/test/deferred_statement_test.dart
@@ -6,6 +6,7 @@
import 'package:js_ast/js_ast.dart';
class _DeferredStatement extends DeferredStatement {
+ @override
final Statement statement;
_DeferredStatement(this.statement);
diff --git a/pkg/js_ast/test/printer_callback_test.dart b/pkg/js_ast/test/printer_callback_test.dart
index a54ddbc..f5477ba 100644
--- a/pkg/js_ast/test/printer_callback_test.dart
+++ b/pkg/js_ast/test/printer_callback_test.dart
@@ -166,7 +166,9 @@
];
class FixedName extends Name {
+ @override
final String name;
+ @override
String get key => name;
FixedName(this.name);
@@ -207,6 +209,7 @@
String tag(int value) => '@$value';
+ @override
void enterNode(Node node, int startPosition) {
int value = id(node);
if (mode == TestMode.ENTER) {
@@ -214,6 +217,7 @@
}
}
+ @override
void exitNode(
Node node, int startPosition, int endPosition, int delimiterPosition) {
int value = id(node);
@@ -224,6 +228,7 @@
}
}
+ @override
String getText() {
String text = super.getText();
int offset = 0;
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index f694613b..e2b8a40 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -5140,7 +5140,7 @@
Deserializer::InitializeHeader(property, kWeakPropertyCid,
WeakProperty::InstanceSize());
ReadFromTo(property);
- property->untag()->next_ = WeakProperty::null();
+ property->untag()->next_seen_by_gc_ = WeakProperty::null();
}
}
};
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index cab9a8e..e7778e6 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -3280,6 +3280,12 @@
#undef __
#define __ assembler_->
+#if defined(VFPv3_D32)
+static const RegisterSet kVolatileFpuRegisters(0, 0xFF0F); // Q0-Q3, Q8-Q15
+#else
+static const RegisterSet kVolatileFpuRegisters(0, 0x000F); // Q0-Q3
+#endif
+
LeafRuntimeScope::LeafRuntimeScope(Assembler* assembler,
intptr_t frame_size,
bool preserve_registers)
@@ -3291,16 +3297,7 @@
kDartVolatileCpuRegs | (1 << PP) | (1 << FP) | (1 << LR), 0));
COMPILE_ASSERT((kDartVolatileCpuRegs & (1 << PP)) == 0);
- // Preserve all volatile FPU registers.
- DRegister firstv = EvenDRegisterOf(kDartFirstVolatileFpuReg);
- DRegister lastv = OddDRegisterOf(kDartLastVolatileFpuReg);
- if ((lastv - firstv + 1) >= 16) {
- DRegister mid = static_cast<DRegister>(firstv + 16);
- __ vstmd(DB_W, SP, mid, lastv - mid + 1);
- __ vstmd(DB_W, SP, firstv, 16);
- } else {
- __ vstmd(DB_W, SP, firstv, lastv - firstv + 1);
- }
+ __ PushRegisters(kVolatileFpuRegisters);
} else {
SPILLS_LR_TO_FRAME(__ EnterFrame((1 << FP) | (1 << LR), 0));
// These registers must always be preserved.
@@ -3330,7 +3327,7 @@
// and ensure proper alignment of the stack frame.
// We need to restore it before restoring registers.
const intptr_t kPushedFpuRegisterSize =
- kDartVolatileFpuRegCount * kFpuRegisterSize;
+ kVolatileFpuRegisters.FpuRegisterCount() * kFpuRegisterSize;
COMPILE_ASSERT(PP < FP);
COMPILE_ASSERT((kDartVolatileCpuRegs & (1 << PP)) == 0);
@@ -3340,16 +3337,7 @@
kDartVolatileCpuRegCount * target::kWordSize + kPushedFpuRegisterSize;
__ AddImmediate(SP, FP, -kPushedRegistersSize);
- // Restore all volatile FPU registers.
- DRegister firstv = EvenDRegisterOf(kDartFirstVolatileFpuReg);
- DRegister lastv = OddDRegisterOf(kDartLastVolatileFpuReg);
- if ((lastv - firstv + 1) >= 16) {
- DRegister mid = static_cast<DRegister>(firstv + 16);
- __ vldmd(IA_W, SP, firstv, 16);
- __ vldmd(IA_W, SP, mid, lastv - mid + 1);
- } else {
- __ vldmd(IA_W, SP, firstv, lastv - firstv + 1);
- }
+ __ PopRegisters(kVolatileFpuRegisters);
// Restore volatile CPU registers.
RESTORES_LR_FROM_FRAME(__ LeaveFrame(kDartVolatileCpuRegs | (1 << PP) |
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index a8d33d5..7b43812 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -571,9 +571,6 @@
#else
const int kDartVolatileCpuRegCount = 5;
#endif
-const QRegister kDartFirstVolatileFpuReg = Q0;
-const QRegister kDartLastVolatileFpuReg = Q3;
-const int kDartVolatileFpuRegCount = 4;
#define R(reg) (static_cast<RegList>(1) << (reg))
diff --git a/runtime/vm/heap/gc_shared.cc b/runtime/vm/heap/gc_shared.cc
new file mode 100644
index 0000000..65f56c3
--- /dev/null
+++ b/runtime/vm/heap/gc_shared.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Logic shared between the Scavenger and Marker.
+
+#include "vm/heap/gc_shared.h"
+
+#include "vm/dart_api_state.h"
+#include "vm/heap/scavenger.h"
+#include "vm/log.h"
+#include "vm/message_handler.h"
+#include "vm/object.h"
+
+namespace dart {
+
+void GCLinkedLists::Release() {
+#define FOREACH(type, var) var.Release();
+ GC_LINKED_LIST(FOREACH)
+#undef FOREACH
+}
+
+bool GCLinkedLists::IsEmpty() {
+#define FOREACH(type, var) \
+ if (!var.IsEmpty()) { \
+ return false; \
+ }
+ GC_LINKED_LIST(FOREACH)
+ return true;
+#undef FOREACH
+}
+
+void GCLinkedLists::FlushInto(GCLinkedLists* to) {
+#define FOREACH(type, var) var.FlushInto(&to->var);
+ GC_LINKED_LIST(FOREACH)
+#undef FOREACH
+}
+
+} // namespace dart
diff --git a/runtime/vm/heap/gc_shared.h b/runtime/vm/heap/gc_shared.h
new file mode 100644
index 0000000..3b42241
--- /dev/null
+++ b/runtime/vm/heap/gc_shared.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for detail_s. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Logic shared between the Scavenger and Marker.
+
+#ifndef RUNTIME_VM_HEAP_GC_SHARED_H_
+#define RUNTIME_VM_HEAP_GC_SHARED_H_
+
+#include "vm/compiler/runtime_api.h"
+#if defined(SHOULD_NOT_INCLUDE_RUNTIME)
+#error "Should not include runtime"
+#endif
+
+#include "vm/dart_api_state.h"
+#include "vm/heap/scavenger.h"
+#include "vm/log.h"
+#include "vm/message_handler.h"
+#include "vm/object.h"
+
+namespace dart {
+
+// These object types have a linked list chaining all pending objects when
+// processing these in the GC.
+// The field should not be visited by pointer visitors.
+// The field should only be set during a GC.
+//
+// Macro params:
+// - type
+// - variable name
+#define GC_LINKED_LIST(V) \
+ V(WeakProperty, weak_properties) \
+ V(WeakReference, weak_references)
+
+template <typename Type, typename PtrType>
+class GCLinkedList {
+ public:
+ void Enqueue(PtrType ptr) {
+ ptr->untag()->next_seen_by_gc_ = head_;
+ if (head_ == Type::null()) {
+ tail_ = ptr;
+ }
+ head_ = ptr;
+ }
+
+ void FlushInto(GCLinkedList<Type, PtrType>* to) {
+ if (to->head_ == Type::null()) {
+ ASSERT(to->tail_ == Type::null());
+ to->head_ = head_;
+ to->tail_ = tail_;
+ } else {
+ ASSERT(to->tail_ != Type::null());
+ ASSERT(to->tail_->untag()->next_seen_by_gc() == Type::null());
+ to->tail_->untag()->next_seen_by_gc_ = head_;
+ to->tail_ = tail_;
+ }
+ Release();
+ }
+
+ PtrType Release() {
+ PtrType return_value = head_;
+ head_ = Type::null();
+ tail_ = Type::null();
+ return return_value;
+ }
+
+ bool IsEmpty() { return head_ == Type::null() && tail_ == Type::null(); }
+
+ private:
+ PtrType head_ = Type::null();
+ PtrType tail_ = Type::null();
+};
+
+struct GCLinkedLists {
+ void Release();
+ bool IsEmpty();
+ void FlushInto(GCLinkedLists* to);
+
+#define FOREACH(type, var) GCLinkedList<type, type##Ptr> var;
+ GC_LINKED_LIST(FOREACH)
+#undef FOREACH
+};
+
+} // namespace dart
+
+#endif // RUNTIME_VM_HEAP_GC_SHARED_H_
diff --git a/runtime/vm/heap/heap_sources.gni b/runtime/vm/heap/heap_sources.gni
index de6d25e..a8e8d99 100644
--- a/runtime/vm/heap/heap_sources.gni
+++ b/runtime/vm/heap/heap_sources.gni
@@ -11,6 +11,8 @@
"compactor.h",
"freelist.cc",
"freelist.h",
+ "gc_shared.cc",
+ "gc_shared.h",
"heap.cc",
"heap.h",
"marker.cc",
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 3309815..a797c39 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -4,9 +4,11 @@
#include "vm/heap/marker.h"
+#include "platform/assert.h"
#include "platform/atomic.h"
#include "vm/allocation.h"
#include "vm/dart_api_state.h"
+#include "vm/heap/gc_shared.h"
#include "vm/heap/pages.h"
#include "vm/heap/pointer_block.h"
#include "vm/isolate.h"
@@ -14,6 +16,7 @@
#include "vm/object_id_ring.h"
#include "vm/raw_object.h"
#include "vm/stack_frame.h"
+#include "vm/tagged_pointer.h"
#include "vm/thread_barrier.h"
#include "vm/thread_pool.h"
#include "vm/thread_registry.h"
@@ -34,34 +37,31 @@
page_space_(page_space),
work_list_(marking_stack),
deferred_work_list_(deferred_marking_stack),
- delayed_weak_properties_(WeakProperty::null()),
- delayed_weak_properties_tail_(WeakProperty::null()),
- delayed_weak_references_(WeakReference::null()),
- delayed_weak_references_tail_(WeakReference::null()),
marked_bytes_(0),
marked_micros_(0) {
ASSERT(thread_->isolate_group() == isolate_group);
}
- ~MarkingVisitorBase() {
- ASSERT(delayed_weak_properties_ == WeakProperty::null());
- ASSERT(delayed_weak_references_ == WeakReference::null());
- }
+ ~MarkingVisitorBase() { ASSERT(delayed_.IsEmpty()); }
uintptr_t marked_bytes() const { return marked_bytes_; }
int64_t marked_micros() const { return marked_micros_; }
void AddMicros(int64_t micros) { marked_micros_ += micros; }
+ static bool IsMarked(ObjectPtr raw) {
+ ASSERT(raw->IsHeapObject());
+ ASSERT(raw->IsOldObject());
+ return raw->untag()->IsMarked();
+ }
+
bool ProcessPendingWeakProperties() {
bool more_to_mark = false;
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_tail_ = delayed_weak_properties_ =
- WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Release();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
ObjectPtr raw_key = cur_weak->untag()->key();
// Reset the next pointer in the weak property.
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
if (raw_key->IsSmiOrNewObject() || raw_key->untag()->IsMarked()) {
ObjectPtr raw_val = cur_weak->untag()->value();
if (!raw_val->IsSmiOrNewObject() && !raw_val->untag()->IsMarked()) {
@@ -73,7 +73,8 @@
cur_weak->untag()->VisitPointersNonvirtual(this);
} else {
// Requeue this weak property to be handled later.
- EnqueueWeakProperty(cur_weak);
+ ASSERT(IsMarked(cur_weak));
+ delayed_.weak_properties.Enqueue(cur_weak);
}
// Advance to next weak property in the queue.
cur_weak = next_weak;
@@ -182,34 +183,6 @@
}
}
- void EnqueueWeakProperty(WeakPropertyPtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsOldObject());
- ASSERT(raw_weak->IsWeakProperty());
- ASSERT(raw_weak->untag()->IsMarked());
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakPropertyPtr(WeakProperty::null()));
- raw_weak->untag()->next_ = delayed_weak_properties_;
- if (delayed_weak_properties_ == WeakProperty::null()) {
- delayed_weak_properties_tail_ = raw_weak;
- }
- delayed_weak_properties_ = raw_weak;
- }
-
- void EnqueueWeakReference(WeakReferencePtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsOldObject());
- ASSERT(raw_weak->IsWeakReference());
- ASSERT(raw_weak->untag()->IsMarked());
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakReferencePtr(WeakReference::null()));
- raw_weak->untag()->next_ = delayed_weak_references_;
- if (delayed_weak_references_ == WeakReference::null()) {
- delayed_weak_references_tail_ = raw_weak;
- }
- delayed_weak_references_ = raw_weak;
- }
-
intptr_t ProcessWeakProperty(WeakPropertyPtr raw_weak) {
// The fate of the weak property is determined by its key.
ObjectPtr raw_key =
@@ -218,7 +191,8 @@
if (raw_key->IsHeapObject() && raw_key->IsOldObject() &&
!raw_key->untag()->IsMarked()) {
// Key was white. Enqueue the weak property.
- EnqueueWeakProperty(raw_weak);
+ ASSERT(IsMarked(raw_weak));
+ delayed_.weak_properties.Enqueue(raw_weak);
return raw_weak->untag()->HeapSize();
}
// Key is gray or black. Make the weak property black.
@@ -235,7 +209,8 @@
!raw_target->untag()->IsMarked()) {
// Target was white. Enqueue the weak reference. It is potentially dead.
// It might still be made alive by weak properties in next rounds.
- EnqueueWeakReference(raw_weak);
+ ASSERT(IsMarked(raw_weak));
+ delayed_.weak_references.Enqueue(raw_weak);
}
// Always visit the type argument.
ObjectPtr raw_type_arguments =
@@ -282,12 +257,11 @@
}
void MournWeakProperties() {
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_ = WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Release();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
RELEASE_ASSERT(!cur_weak->untag()->key()->untag()->IsMarked());
WeakProperty::Clear(cur_weak);
cur_weak = next_weak;
@@ -295,72 +269,58 @@
}
void MournWeakReferences() {
- WeakReferencePtr cur_weak = delayed_weak_references_;
- delayed_weak_references_ = WeakReference::null();
+ WeakReferencePtr cur_weak = delayed_.weak_references.Release();
while (cur_weak != WeakReference::null()) {
WeakReferencePtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
- cur_weak->untag()->next_ = WeakReference::null();
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_ = WeakReference::null();
+
// If we did not mark the target through a weak property in a later round,
// then the target is dead and we should clear it.
- if (!cur_weak->untag()->target()->untag()->IsMarked()) {
- WeakReference::Clear(cur_weak);
- }
+ SetNullIfCollected(cur_weak->heap_base(), &cur_weak->untag()->target_);
+
cur_weak = next_weak;
}
}
+ // Returns whether the object referred to in `ptr_address` was GCed this GC.
+ static bool SetNullIfCollected(uword heap_base,
+ CompressedObjectPtr* ptr_address) {
+ ObjectPtr raw = ptr_address->Decompress(heap_base);
+ if (raw.IsRawNull()) {
+ // Object already null before this GC.
+ return false;
+ }
+ if (raw.IsNewObject()) {
+ // Object not touched during this GC.
+ return false;
+ }
+ if (raw->untag()->IsMarked()) {
+ return false;
+ }
+ *ptr_address = Object::null();
+ return true;
+ }
+
bool WaitForWork(RelaxedAtomic<uintptr_t>* num_busy) {
return work_list_.WaitForWork(num_busy);
}
- void Flush(WeakPropertyPtr* weak_properties_head,
- WeakPropertyPtr* weak_properties_tail,
- WeakReferencePtr* weak_references_head,
- WeakReferencePtr* weak_references_tail) {
+ void Flush(GCLinkedLists* global_list) {
work_list_.Flush();
deferred_work_list_.Flush();
-
- if (*weak_properties_head == WeakProperty::null()) {
- *weak_properties_head = delayed_weak_properties_;
- *weak_properties_tail = delayed_weak_properties_tail_;
- } else {
- (*weak_properties_tail)->untag()->next_ = delayed_weak_properties_;
- *weak_properties_tail = delayed_weak_properties_tail_;
- }
- delayed_weak_properties_tail_ = delayed_weak_properties_ =
- WeakProperty::null();
-
- if (*weak_references_head == WeakReference::null()) {
- *weak_references_head = delayed_weak_references_;
- *weak_references_tail = delayed_weak_references_tail_;
- } else {
- (*weak_references_tail)->untag()->next_ = delayed_weak_references_;
- *weak_references_tail = delayed_weak_references_tail_;
- }
- delayed_weak_references_tail_ = delayed_weak_references_ =
- WeakReference::null();
+ delayed_.FlushInto(global_list);
}
- void Adopt(WeakPropertyPtr weak_properties_head,
- WeakPropertyPtr weak_properties_tail,
- WeakReferencePtr weak_references_head,
- WeakReferencePtr weak_references_tail) {
- ASSERT(delayed_weak_properties_ == WeakProperty::null());
- ASSERT(delayed_weak_properties_tail_ == WeakProperty::null());
- ASSERT(delayed_weak_references_ == WeakReference::null());
- ASSERT(delayed_weak_references_tail_ == WeakReference::null());
- delayed_weak_properties_ = weak_properties_head;
- delayed_weak_properties_tail_ = weak_properties_tail;
- delayed_weak_references_ = weak_references_head;
- delayed_weak_references_tail_ = weak_references_tail;
+ void Adopt(GCLinkedLists* other) {
+ ASSERT(delayed_.IsEmpty());
+ other->FlushInto(&delayed_);
}
void AbandonWork() {
work_list_.AbandonWork();
deferred_work_list_.AbandonWork();
- delayed_weak_properties_ = WeakProperty::null();
- delayed_weak_references_ = WeakReference::null();
+ delayed_.Release();
}
private:
@@ -430,10 +390,7 @@
PageSpace* page_space_;
MarkerWorkList work_list_;
MarkerWorkList deferred_work_list_;
- WeakPropertyPtr delayed_weak_properties_;
- WeakPropertyPtr delayed_weak_properties_tail_;
- WeakReferencePtr delayed_weak_references_;
- WeakReferencePtr delayed_weak_references_tail_;
+ GCLinkedLists delayed_;
uintptr_t marked_bytes_;
int64_t marked_micros_;
@@ -746,6 +703,7 @@
// Phase 3: Weak processing and statistics.
visitor_->MournWeakProperties();
visitor_->MournWeakReferences();
+
marker_->IterateWeakRoots(thread);
int64_t stop = OS::GetCurrentMonotonicMicros();
visitor_->AddMicros(stop - start);
@@ -998,10 +956,7 @@
RelaxedAtomic<uintptr_t> num_busy = 0;
// Phase 1: Iterate over roots and drain marking stack in tasks.
- WeakPropertyPtr weak_properties_head = WeakProperty::null();
- WeakPropertyPtr weak_properties_tail = WeakProperty::null();
- WeakReferencePtr weak_references_head = WeakReference::null();
- WeakReferencePtr weak_references_tail = WeakReference::null();
+ GCLinkedLists global_list;
for (intptr_t i = 0; i < num_tasks; ++i) {
SyncMarkingVisitor* visitor = visitors_[i];
@@ -1013,12 +968,12 @@
&marking_stack_, &deferred_marking_stack_);
visitors_[i] = visitor;
}
+
// Move all work from local blocks to the global list. Any given
// visitor might not get to run if it fails to reach TryEnter soon
// enough, and we must fail to visit objects but they're sitting in
// such a visitor's local blocks.
- visitor->Flush(&weak_properties_head, &weak_properties_tail,
- &weak_references_head, &weak_references_tail);
+ visitor->Flush(&global_list);
// Need to move weak property list too.
if (i < (num_tasks - 1)) {
@@ -1029,8 +984,7 @@
ASSERT(result);
} else {
// Last worker is the main thread.
- visitor->Adopt(weak_properties_head, weak_properties_tail,
- weak_references_head, weak_references_tail);
+ visitor->Adopt(&global_list);
ParallelMarkTask task(this, isolate_group_, &marking_stack_, barrier,
visitor, &num_busy);
task.RunEnteredIsolateGroup();
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index e8b433a..75b2519 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -4,11 +4,14 @@
#include "vm/heap/scavenger.h"
+#include "platform/assert.h"
#include "platform/leak_sanitizer.h"
+#include "vm/class_id.h"
#include "vm/dart.h"
#include "vm/dart_api_state.h"
#include "vm/flag_list.h"
#include "vm/heap/become.h"
+#include "vm/heap/gc_shared.h"
#include "vm/heap/pages.h"
#include "vm/heap/pointer_block.h"
#include "vm/heap/safepoint.h"
@@ -20,6 +23,7 @@
#include "vm/object.h"
#include "vm/object_id_ring.h"
#include "vm/object_set.h"
+#include "vm/port.h"
#include "vm/stack_frame.h"
#include "vm/thread_barrier.h"
#include "vm/thread_registry.h"
@@ -131,13 +135,8 @@
freelist_(freelist),
bytes_promoted_(0),
visiting_old_object_(nullptr),
- promoted_list_(promotion_stack),
- delayed_weak_properties_(WeakProperty::null()),
- delayed_weak_references_(WeakReference::null()) {}
- ~ScavengerVisitorBase() {
- ASSERT(delayed_weak_properties_ == WeakProperty::null());
- ASSERT(delayed_weak_references_ == WeakReference::null());
- }
+ promoted_list_(promotion_stack) {}
+ ~ScavengerVisitorBase() { ASSERT(delayed_.IsEmpty()); }
virtual void VisitTypedDataViewPointers(TypedDataViewPtr view,
CompressedObjectPtr* first,
@@ -308,13 +307,15 @@
void AbandonWork() {
promoted_list_.AbandonWork();
- delayed_weak_properties_ = WeakProperty::null();
- delayed_weak_references_ = WeakReference::null();
+ delayed_.Release();
}
NewPage* head() const { return head_; }
NewPage* tail() const { return tail_; }
+ static bool SetNullIfCollected(uword heap_base,
+ CompressedObjectPtr* ptr_address);
+
private:
void UpdateStoreBuffer(ObjectPtr obj) {
ASSERT(obj->IsHeapObject());
@@ -511,8 +512,13 @@
inline void ProcessToSpace();
DART_FORCE_INLINE intptr_t ProcessCopied(ObjectPtr raw_obj);
inline void ProcessPromotedList();
- inline void EnqueueWeakProperty(WeakPropertyPtr raw_weak);
- inline void EnqueueWeakReference(WeakReferencePtr raw_weak);
+
+ bool IsNotForwarding(ObjectPtr raw) {
+ ASSERT(raw->IsHeapObject());
+ ASSERT(raw->IsNewObject());
+ return !IsForwarding(ReadHeaderRelaxed(raw));
+ }
+
inline void MournWeakProperties();
inline void MournOrUpdateWeakReferences();
@@ -523,10 +529,8 @@
FreeList* freelist_;
intptr_t bytes_promoted_;
ObjectPtr visiting_old_object_;
-
PromotionWorkList promoted_list_;
- WeakPropertyPtr delayed_weak_properties_;
- WeakReferencePtr delayed_weak_references_;
+ GCLinkedLists delayed_;
NewPage* head_ = nullptr;
NewPage* tail_ = nullptr; // Allocating from here.
@@ -1323,11 +1327,10 @@
// Finished this round of scavenging. Process the pending weak properties
// for which the keys have become reachable. Potentially this adds more
// objects to the to space.
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_ = WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Release();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
// Promoted weak properties are not enqueued. So we can guarantee that
// we do not need to think about store barriers here.
ASSERT(cur_weak->IsNewObject());
@@ -1341,11 +1344,12 @@
ASSERT(from_->Contains(raw_addr));
uword header = ReadHeaderRelaxed(raw_key);
// Reset the next pointer in the weak property.
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
if (IsForwarding(header)) {
cur_weak->untag()->VisitPointersNonvirtual(this);
} else {
- EnqueueWeakProperty(cur_weak);
+ ASSERT(IsNotForwarding(cur_weak));
+ delayed_.weak_properties.Enqueue(cur_weak);
}
// Advance to next weak property in the queue.
cur_weak = next_weak;
@@ -1378,38 +1382,6 @@
}
template <bool parallel>
-void ScavengerVisitorBase<parallel>::EnqueueWeakProperty(
- WeakPropertyPtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsNewObject());
- ASSERT(raw_weak->IsWeakProperty());
-#if defined(DEBUG)
- uword header = ReadHeaderRelaxed(raw_weak);
- ASSERT(!IsForwarding(header));
-#endif // defined(DEBUG)
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakPropertyPtr(WeakProperty::null()));
- raw_weak->untag()->next_ = delayed_weak_properties_;
- delayed_weak_properties_ = raw_weak;
-}
-
-template <bool parallel>
-void ScavengerVisitorBase<parallel>::EnqueueWeakReference(
- WeakReferencePtr raw_weak) {
- ASSERT(raw_weak->IsHeapObject());
- ASSERT(raw_weak->IsNewObject());
- ASSERT(raw_weak->IsWeakReference());
-#if defined(DEBUG)
- uword header = ReadHeaderRelaxed(raw_weak);
- ASSERT(!IsForwarding(header));
-#endif // defined(DEBUG)
- ASSERT(raw_weak->untag()->next_ ==
- CompressedWeakReferencePtr(WeakReference::null()));
- raw_weak->untag()->next_ = delayed_weak_references_;
- delayed_weak_references_ = raw_weak;
-}
-
-template <bool parallel>
intptr_t ScavengerVisitorBase<parallel>::ProcessCopied(ObjectPtr raw_obj) {
intptr_t class_id = raw_obj->GetClassId();
if (UNLIKELY(class_id == kWeakPropertyCid)) {
@@ -1420,7 +1392,8 @@
uword header = ReadHeaderRelaxed(raw_key);
if (!IsForwarding(header)) {
// Key is white. Enqueue the weak property.
- EnqueueWeakProperty(raw_weak);
+ ASSERT(IsNotForwarding(raw_weak));
+ delayed_.weak_properties.Enqueue(raw_weak);
return raw_weak->untag()->HeapSize();
}
}
@@ -1434,7 +1407,8 @@
if (!IsForwarding(header)) {
// Target is white. Enqueue the weak reference. Always visit type
// arguments.
- EnqueueWeakReference(raw_weak);
+ ASSERT(IsNotForwarding(raw_weak));
+ delayed_.weak_references.Enqueue(raw_weak);
#if !defined(DART_COMPRESSED_POINTERS)
ScavengePointer(&raw_weak->untag()->type_arguments_);
#else
@@ -1507,13 +1481,12 @@
// The queued weak properties at this point do not refer to reachable keys,
// so we clear their key and value fields.
- WeakPropertyPtr cur_weak = delayed_weak_properties_;
- delayed_weak_properties_ = WeakProperty::null();
+ WeakPropertyPtr cur_weak = delayed_.weak_properties.Release();
while (cur_weak != WeakProperty::null()) {
WeakPropertyPtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
// Reset the next pointer in the weak property.
- cur_weak->untag()->next_ = WeakProperty::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakProperty::null();
#if defined(DEBUG)
ObjectPtr raw_key = cur_weak->untag()->key();
@@ -1537,31 +1510,48 @@
// The queued weak references at this point either should have their target
// updated or should be cleared.
- WeakReferencePtr cur_weak = delayed_weak_references_;
- delayed_weak_references_ = WeakReference::null();
+ WeakReferencePtr cur_weak = delayed_.weak_references.Release();
while (cur_weak != WeakReference::null()) {
WeakReferencePtr next_weak =
- cur_weak->untag()->next_.Decompress(cur_weak->heap_base());
+ cur_weak->untag()->next_seen_by_gc_.Decompress(cur_weak->heap_base());
// Reset the next pointer in the weak reference.
- cur_weak->untag()->next_ = WeakReference::null();
+ cur_weak->untag()->next_seen_by_gc_ = WeakReference::null();
- ObjectPtr raw_target = cur_weak->untag()->target();
- uword raw_addr = UntaggedObject::ToAddr(raw_target);
- uword header = *reinterpret_cast<uword*>(raw_addr);
- if (IsForwarding(header)) {
- // Get the new location of the object.
- cur_weak->untag()->target_ = ForwardedObj(header);
- } else {
- ASSERT(raw_target->IsHeapObject());
- ASSERT(raw_target->IsNewObject());
- WeakReference::Clear(cur_weak);
- }
+ // If we did not mark the target through a weak property in a later round,
+ // then the target is dead and we should clear it.
+ SetNullIfCollected(cur_weak->heap_base(), &cur_weak->untag()->target_);
// Advance to next weak reference in the queue.
cur_weak = next_weak;
}
}
+// Returns whether the object referred to in `ptr_address` was GCed this GC.
+template <bool parallel>
+bool ScavengerVisitorBase<parallel>::SetNullIfCollected(
+ uword heap_base,
+ CompressedObjectPtr* ptr_address) {
+ ObjectPtr raw = ptr_address->Decompress(heap_base);
+ if (raw.IsRawNull()) {
+ // Object already null before this GC.
+ return false;
+ }
+ if (raw.IsOldObject()) {
+ // Object not touched during this GC.
+ return false;
+ }
+ uword header = *reinterpret_cast<uword*>(UntaggedObject::ToAddr(raw));
+ if (IsForwarding(header)) {
+ // Get the new location of the object.
+ *ptr_address = ForwardedObj(header);
+ return false;
+ }
+ ASSERT(raw->IsHeapObject());
+ ASSERT(raw->IsNewObject());
+ *ptr_address = Object::null();
+ return true;
+}
+
void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const {
ASSERT(Thread::Current()->IsAtSafepoint() ||
(Thread::Current()->task_kind() == Thread::kMarkerTask) ||
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 2f8c8cc..59450e8 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2422,15 +2422,15 @@
head = next;
} while (head != nullptr);
head = reversed_head;
-
if (Service::profiler_stream.enabled() && !IsSystemIsolate(this)) {
- SampleBlockListProcessor buffer(head);
StackZone zone(thread);
- HandleScope handle_scope(thread);
- StreamableSampleFilter filter(main_port());
- Profile profile;
- profile.Build(thread, &filter, &buffer);
- if (profile.sample_count() > 0) {
+ SampleBlockListProcessor buffer(head);
+ if (buffer.HasStreamableSamples(thread)) {
+ HandleScope handle_scope(thread);
+ StreamableSampleFilter filter(main_port());
+ Profile profile;
+ profile.Build(thread, &filter, &buffer);
+ ASSERT(profile.sample_count() > 0);
ServiceEvent event(this, ServiceEvent::kCpuSamples);
event.set_cpu_profile(&profile);
Service::HandleEvent(&event);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 683dd4d..b1c471e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5919,9 +5919,7 @@
static intptr_t UnroundedSize(intptr_t length) {
return HeaderSize() + length;
}
- static intptr_t InstanceSize() {
- return 0;
- }
+ static intptr_t InstanceSize() { return 0; }
static intptr_t InstanceSize(intptr_t length) {
return RoundedAllocationSize(UnroundedSize(length));
}
@@ -11979,7 +11977,7 @@
}
static void Clear(WeakPropertyPtr raw_weak) {
- ASSERT(raw_weak->untag()->next_ ==
+ ASSERT(raw_weak->untag()->next_seen_by_gc_ ==
CompressedWeakPropertyPtr(WeakProperty::null()));
// This action is performed by the GC. No barrier.
raw_weak->untag()->key_ = Object::null();
@@ -12012,7 +12010,7 @@
}
static void Clear(WeakReferencePtr raw_weak) {
- ASSERT(raw_weak->untag()->next_ ==
+ ASSERT(raw_weak->untag()->next_seen_by_gc_ ==
CompressedWeakReferencePtr(WeakReference::null()));
// This action is performed by the GC. No barrier.
raw_weak->untag()->target_ = Object::null();
diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc
index 638febe..0998320 100644
--- a/runtime/vm/object_graph_copy.cc
+++ b/runtime/vm/object_graph_copy.cc
@@ -1362,8 +1362,8 @@
Object::null());
// To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here.
Base::StoreCompressedPointerNoBarrier(
- Types::GetWeakPropertyPtr(to), OFFSET_OF(UntaggedWeakProperty, next_),
- Object::null());
+ Types::GetWeakPropertyPtr(to),
+ OFFSET_OF(UntaggedWeakProperty, next_seen_by_gc_), Object::null());
Base::EnqueueWeakProperty(from);
}
@@ -1380,8 +1380,8 @@
from, to, OFFSET_OF(UntaggedWeakReference, type_arguments_));
// To satisfy some ASSERT()s in GC we'll use Object:null() explicitly here.
Base::StoreCompressedPointerNoBarrier(
- Types::GetWeakReferencePtr(to), OFFSET_OF(UntaggedWeakReference, next_),
- Object::null());
+ Types::GetWeakReferencePtr(to),
+ OFFSET_OF(UntaggedWeakReference, next_seen_by_gc_), Object::null());
Base::EnqueueWeakReference(from);
}
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index b0261f0..d8ae4af 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -713,6 +713,38 @@
return buffer;
}
+bool SampleBlockListProcessor::HasStreamableSamples(Thread* thread) {
+ ReusableGrowableObjectArrayHandleScope reusable_array_handle_scope(thread);
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
+ ASSERT(isolate->tag_table() != GrowableObjectArray::null());
+ GrowableObjectArray& tag_table = reusable_array_handle_scope.Handle();
+ tag_table ^= isolate->tag_table();
+ UserTag& tag = UserTag::Handle(zone);
+ while (head_ != nullptr) {
+ if (head_->HasStreamableSamples(tag_table, &tag)) {
+ return true;
+ }
+ head_ = head_->next_free_;
+ }
+ return false;
+}
+
+bool SampleBlock::HasStreamableSamples(const GrowableObjectArray& tag_table,
+ UserTag* tag) {
+ for (intptr_t i = 0; i < capacity_; ++i) {
+ Sample* sample = At(i);
+ uword sample_tag = sample->user_tag();
+ for (intptr_t j = 0; j < tag_table.Length(); ++j) {
+ *tag ^= tag_table.At(j);
+ if (tag->tag() == sample_tag && tag->streamable()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
ProcessedSampleBuffer* SampleBlockBuffer::BuildProcessedSampleBuffer(
SampleFilter* filter,
ProcessedSampleBuffer* buffer) {
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index c68c792..dc7e10b 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -756,6 +756,8 @@
virtual Sample* ReserveSampleAndLink(Sample* previous);
protected:
+ bool HasStreamableSamples(const GrowableObjectArray& tag_table, UserTag* tag);
+
Isolate* owner_ = nullptr;
bool allocation_block_ = false;
@@ -882,6 +884,10 @@
SampleFilter* filter,
ProcessedSampleBuffer* buffer = nullptr);
+ // Returns true when at least one sample in the sample block list has a user
+ // tag with CPU sample streaming enabled.
+ bool HasStreamableSamples(Thread* thread);
+
private:
SampleBlock* head_;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 5a084c5..98c4e48 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -3265,7 +3265,7 @@
class UntaggedWeakProperty : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(WeakProperty);
- COMPRESSED_POINTER_FIELD(ObjectPtr, key)
+ COMPRESSED_POINTER_FIELD(ObjectPtr, key) // Weak reference.
VISIT_FROM(key)
COMPRESSED_POINTER_FIELD(ObjectPtr, value)
VISIT_TO(value)
@@ -3273,8 +3273,10 @@
// Linked list is chaining all pending weak properties. Not visited by
// pointer visitors.
- CompressedWeakPropertyPtr next_;
+ COMPRESSED_POINTER_FIELD(WeakPropertyPtr, next_seen_by_gc)
+ template <typename Type, typename PtrType>
+ friend class GCLinkedList;
friend class GCMarker;
template <bool>
friend class MarkingVisitorBase;
@@ -3288,7 +3290,7 @@
class UntaggedWeakReference : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(WeakReference);
- COMPRESSED_POINTER_FIELD(ObjectPtr, target)
+ COMPRESSED_POINTER_FIELD(ObjectPtr, target) // Weak reference.
VISIT_FROM(target)
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, type_arguments)
VISIT_TO(type_arguments)
@@ -3296,8 +3298,10 @@
// Linked list is chaining all pending weak properties. Not visited by
// pointer visitors.
- CompressedWeakReferencePtr next_;
+ COMPRESSED_POINTER_FIELD(WeakReferencePtr, next_seen_by_gc)
+ template <typename Type, typename PtrType>
+ friend class GCLinkedList;
friend class GCMarker;
template <bool>
friend class MarkingVisitorBase;
diff --git a/tests/modular/issue226161959/b.dart b/tests/modular/issue226161959/b.dart
new file mode 100644
index 0000000..fdcd5b5
--- /dev/null
+++ b/tests/modular/issue226161959/b.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'm.dart';
+
+class B extends A {}
+
+class C extends B with M {}
diff --git a/tests/modular/issue226161959/m.dart b/tests/modular/issue226161959/m.dart
new file mode 100644
index 0000000..56cb29a
--- /dev/null
+++ b/tests/modular/issue226161959/m.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ String foo() => 'A';
+}
+
+mixin M on A {
+ @override
+ String foo() => 'M' + super.foo();
+}
diff --git a/tests/modular/issue226161959/main.dart b/tests/modular/issue226161959/main.dart
new file mode 100644
index 0000000..4315bee
--- /dev/null
+++ b/tests/modular/issue226161959/main.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+import 'b.dart';
+
+main() {
+ C c = C();
+ Expect.equals('MA', c.foo());
+}
diff --git a/tests/modular/issue226161959/modules.yaml b/tests/modular/issue226161959/modules.yaml
new file mode 100644
index 0000000..31e04b2
--- /dev/null
+++ b/tests/modular/issue226161959/modules.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+dependencies:
+ main: [b, m, expect]
+ b: [m]
+ m: []
diff --git a/tools/VERSION b/tools/VERSION
index 0258b7a..6056e75 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 232
+PRERELEASE 233
PRERELEASE_PATCH 0
\ No newline at end of file