Version 2.11.0-157.0.dev
Merge commit 'd966206c6defa2b52be74642318c780283f24bfb' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 12e1c33..5ef3143 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2020-08-18T15:38:52.410101",
+ "generated": "2020-09-18T09:56:27.880444",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -184,7 +184,7 @@
"name": "dart2js_info",
"rootUri": "../third_party/pkg/dart2js_info",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.3"
},
{
"name": "dart2js_tools",
@@ -207,8 +207,7 @@
{
"name": "dart_style",
"rootUri": "../third_party/pkg_tested/dart_style",
- "packageUri": "lib/",
- "languageVersion": "2.7"
+ "packageUri": "lib/"
},
{
"name": "dartdev",
@@ -348,8 +347,7 @@
{
"name": "js_runtime",
"rootUri": "../sdk/lib/_internal/js_runtime",
- "packageUri": "lib/",
- "languageVersion": "2.10"
+ "packageUri": "lib/"
},
{
"name": "json_rpc_2",
@@ -426,7 +424,7 @@
"name": "native_stack_traces",
"rootUri": "../pkg/native_stack_traces",
"packageUri": "lib/",
- "languageVersion": "2.8"
+ "languageVersion": "2.10"
},
{
"name": "nnbd_migration",
@@ -484,8 +482,7 @@
{
"name": "pub",
"rootUri": "../third_party/pkg/pub",
- "packageUri": "lib/",
- "languageVersion": "2.3"
+ "packageUri": "lib/"
},
{
"name": "pub_semver",
@@ -508,8 +505,7 @@
{
"name": "sdk_library_metadata",
"rootUri": "../sdk/lib/_internal/sdk_library_metadata",
- "packageUri": "lib/",
- "languageVersion": "2.10"
+ "packageUri": "lib/"
},
{
"name": "shelf",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 643c771..9d443f4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,12 @@
### Tools
+#### Dartanalyzer
+
+* Removed the `--use-fasta-parser`, `--preview-dart-2`, and
+ `--enable-assert-initializers` command line options. These options haven't
+ been supported in a while and were no-ops.
+
#### Linter
Updated the Linter to `0.1.119`, which includes:
@@ -55,7 +61,7 @@
deferred loading of types, pass `--no-defer-class-types`. See the original
post on the [unsoundness in the deferred loading algorithm][].
* Enables a new sound deferred splitting algorithm. To explicitly disable
- the new deferred splitting algorithm, pass `--no-new-deferred-split'.
+ the new deferred splitting algorithm, pass `--no-new-deferred-split`.
See the original post on the
[unsoundness in the deferred loading algorithm][].
diff --git a/DEPS b/DEPS
index c6af26a..9000961 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes. It requires access to the dart-build-access group, which EngProd
# has.
- "co19_rev": "b7660861df12eb489243a591e45f251f8cf8c4a8",
+ "co19_rev": "da33ec472443aa14d969bf54b9adc3af71cb6382",
"co19_2_rev": "e48b3090826cf40b8037648f19d211e8eab1b4b6",
# The internal benchmarks to use. See go/dart-benchmarks-internal
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index df90a5f..c2f43d8 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -609,6 +609,11 @@
void parenthesizedExpression(
Expression outerExpression, Expression innerExpression);
+ /// Attempt to promote [variable] to [type]. The client may use this to
+ /// ensure that a variable declaration of the form `var x = expr;` promotes
+ /// `x` to type `X&T` in the circumstance where the type of `expr` is `X&T`.
+ void promote(Variable variable, Type type);
+
/// Retrieves the type that the [variable] is promoted to, if the [variable]
/// is currently promoted. Otherwise returns `null`.
Type promotedType(Variable variable);
@@ -749,7 +754,12 @@
/// Register write of the given [variable] in the current state.
/// [writtenType] should be the type of the value that was written.
- void write(Variable variable, Type writtenType);
+ ///
+ /// This should also be used for the implicit write to a non-final variable in
+ /// its initializer, to ensure that the type is promoted to non-nullable if
+ /// necessary; in this case, [viaInitializer] should be `true`.
+ void write(Variable variable, Type writtenType,
+ {bool viaInitializer = false});
}
/// Alternate implementation of [FlowAnalysis] that prints out inputs and output
@@ -1055,6 +1065,11 @@
}
@override
+ void promote(Variable variable, Type type) {
+ _wrap('promote($variable, $type', () => _wrapped.promote(variable, type));
+ }
+
+ @override
Type promotedType(Variable variable) {
return _wrap(
'promotedType($variable)', () => _wrapped.promotedType(variable),
@@ -1156,9 +1171,12 @@
}
@override
- void write(Variable variable, Type writtenType) {
- _wrap('write($variable, $writtenType)',
- () => _wrapped.write(variable, writtenType));
+ void write(Variable variable, Type writtenType,
+ {bool viaInitializer = false}) {
+ _wrap(
+ 'write($variable, $writtenType, viaInitializer: $viaInitializer)',
+ () => _wrapped.write(variable, writtenType,
+ viaInitializer: viaInitializer));
}
T _wrap<T>(String description, T callback(),
@@ -1770,11 +1788,6 @@
List<Type> newPromotedTypes) =>
false;
- /// Return `true` if the [variable] is a local variable (not a formal
- /// parameter), and it has no declared type (no explicit type, and not
- /// initializer).
- bool isLocalVariableWithoutDeclaredType(Variable variable);
-
/// Determines whether the given [type] is equivalent to the `Never` type.
///
/// A type is equivalent to `Never` if it:
@@ -1985,11 +1998,6 @@
promotedTypes, tested, true, false, writeCaptured);
}
- if (_isPromotableViaInitialization(typeOperations, variable)) {
- return new VariableModel<Variable, Type>(
- [writtenType], tested, true, false, writeCaptured);
- }
-
List<Type> newPromotedTypes = _demoteViaAssignment(
writtenType,
typeOperations,
@@ -2041,26 +2049,6 @@
}
}
- /// We say that a variable `x` is promotable via initialization given
- /// variable model `VM` if `x` is a local variable (not a formal parameter)
- /// and:
- /// * VM = VariableModel(declared, promoted, tested,
- /// assigned, unassigned, captured)
- /// * and `captured` is false
- /// * and `promoted` is empty
- /// * and `x` is declared with no explicit type and no initializer
- /// * and `assigned` is false and `unassigned` is true
- bool _isPromotableViaInitialization<Variable>(
- TypeOperations<Variable, Type> typeOperations,
- Variable variable,
- ) {
- return !writeCaptured &&
- !assigned &&
- unassigned &&
- promotedTypes == null &&
- typeOperations.isLocalVariableWithoutDeclaredType(variable);
- }
-
/// Determines whether a variable with the given [promotedTypes] should be
/// promoted to [writtenType] based on types of interest. If it should,
/// returns an updated promotion chain; otherwise returns [promotedTypes]
@@ -2903,6 +2891,12 @@
}
@override
+ void promote(Variable variable, Type type) {
+ _current =
+ _current.tryPromoteForTypeCheck(typeOperations, variable, type).ifTrue;
+ }
+
+ @override
Type promotedType(Variable variable) {
return _current.infoFor(variable).promotedTypes?.last;
}
@@ -3055,11 +3049,14 @@
}
@override
- void write(Variable variable, Type writtenType) {
- assert(
- _assignedVariables._anywhere._written.contains(variable),
- "Variable is written to, but was not included in "
- "_variablesWrittenAnywhere: $variable");
+ void write(Variable variable, Type writtenType,
+ {bool viaInitializer = false}) {
+ if (!viaInitializer) {
+ assert(
+ _assignedVariables._anywhere._written.contains(variable),
+ "Variable is written to, but was not included in "
+ "_variablesWrittenAnywhere: $variable");
+ }
_current = _current.write(variable, writtenType, typeOperations);
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 0e4375a..2df01db 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -4013,6 +4013,32 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ String
+ name)> templateFinalNotAssignedError = const Template<
+ Message Function(String name)>(
+ messageTemplate:
+ r"""Final variable '#name' must be assigned before it can be used.""",
+ withArguments: _withArgumentsFinalNotAssignedError);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeFinalNotAssignedError =
+ const Code<Message Function(String name)>(
+ "FinalNotAssignedError", templateFinalNotAssignedError,
+ analyzerCodes: <String>["READ_POTENTIALLY_UNASSIGNED_FINAL"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFinalNotAssignedError(String name) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ return new Message(codeFinalNotAssignedError,
+ message:
+ """Final variable '${name}' must be assigned before it can be used.""",
+ arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeForInLoopExactlyOneVariable =
messageForInLoopExactlyOneVariable;
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 92c7bae..86ce5d9 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -1443,6 +1443,54 @@
});
});
+ test('promote promotes to a subtype and sets type of interest', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'num?');
+ h.assignedVariables((vars) {
+ vars.write(x);
+ });
+ h.run((flow) {
+ flow.declare(x, true);
+ expect(flow.promotedType(x), isNull);
+ flow.promote(x, _Type('num'));
+ expect(flow.promotedType(x).type, 'num');
+ // Check that it's a type of interest by promoting and de-promoting.
+ h.if_(h.isType(h.variableRead(x), 'int'), () {
+ expect(flow.promotedType(x).type, 'int');
+ flow.write(x, _Type('num'));
+ expect(flow.promotedType(x).type, 'num');
+ });
+ });
+ });
+
+ test('promote does not promote to a non-subtype', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'num?');
+ h.run((flow) {
+ flow.declare(x, true);
+ expect(flow.promotedType(x), isNull);
+ flow.promote(x, _Type('String'));
+ expect(flow.promotedType(x), isNull);
+ });
+ });
+
+ test('promote does not promote if variable is write-captured', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'num?');
+ var functionNode = _Node();
+ h.assignedVariables(
+ (vars) => vars.function(functionNode, () => vars.write(x)));
+ h.run((flow) {
+ flow.declare(x, true);
+ expect(flow.promotedType(x), isNull);
+ flow.functionExpression_begin(functionNode);
+ flow.write(x, _Type('num'));
+ flow.functionExpression_end();
+ flow.promote(x, _Type('num'));
+ expect(flow.promotedType(x), isNull);
+ });
+ });
+
test('promotedType handles not-yet-seen variables', () {
// Note: this is needed for error recovery in the analyzer.
var h = _Harness();
@@ -2658,21 +2706,6 @@
});
});
});
-
- test('promote via initialization', () {
- var h = _Harness();
- var x = _Var('x', null, isLocalVariableWithoutDeclaredType: true);
-
- var s1 = FlowModel<_Var, _Type>(true).declare(x, false);
- expect(s1.variableInfo, {
- x: _matchVariableModel(chain: null),
- });
-
- var s2 = s1.write(x, _Type('int'), h);
- expect(s2.variableInfo, {
- x: _matchVariableModel(chain: ['int']),
- });
- });
});
group('demotion, to NonNull', () {
@@ -3790,11 +3823,6 @@
}
@override
- bool isLocalVariableWithoutDeclaredType(_Var variable) {
- return variable.isLocalVariableWithoutDeclaredType;
- }
-
- @override
bool isNever(_Type type) {
return type.type == 'Never';
}
@@ -3956,13 +3984,8 @@
class _Var {
final String name;
final _Type type;
- final bool isLocalVariableWithoutDeclaredType;
- _Var(
- this.name,
- this.type, {
- this.isLocalVariableWithoutDeclaredType = false,
- });
+ _Var(this.name, this.type);
@override
String toString() => '$type $name';
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart
index 6425744..3d890e8 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart
@@ -8,7 +8,7 @@
localVariable() {
var x;
x = 1;
- /*int*/ x;
+ x;
x = 2.3;
x;
}
@@ -35,10 +35,10 @@
var x;
if (a) {
x = 0;
- /*int*/ x;
+ x;
} else {
x = 1.2;
- /*double*/ x;
+ x;
}
x;
}
@@ -47,12 +47,83 @@
var x;
if (a) {
x = 0;
- /*int*/ x;
+ x;
} else {
x = 1;
- /*int*/ x;
+ x;
}
- /*int*/ x;
+ x;
+}
+
+localVariable_initialized_promoted_type_var<T>(T t) {
+ if (t is num) {
+ var x = /*T & num*/ t;
+ /*T & num*/ x;
+ // Check that it is a type of interest by promoting and then writing to it
+ if (/*T & num*/ x is int) {
+ /*T & int*/ x;
+ x = /*T & num*/ t;
+ /*T & num*/ x;
+ }
+ }
+}
+
+localVariable_initialized_unpromoted_type_var<T>(T t) {
+ var x = t;
+ x;
+ // Check that `T & Object` is a type of interest, by promoting and then
+ // writing to it
+ if (x is int && t is num) {
+ /*T & int*/ x;
+ x = /*T & num*/ t;
+ /*T & Object*/ x;
+ }
+}
+
+localVariable_initialized_unpromoted_type_var_with_bound<T extends num?>(T t) {
+ var x = t;
+ x;
+ // Check that `T & num` is a type of interest, by promoting and then writing
+ // to it
+ if (x is int && t is double) {
+ /*T & int*/ x;
+ x = /*T & double*/ t;
+ /*T & num*/ x;
+ }
+}
+
+localVariable_initialized_promoted_type_var_typed<T>(T t) {
+ if (t is num) {
+ // TODO(paulberry): This should promote to `T & Object`, because that's the
+ // non-nullable version of T, but it shouldn't promote to `T & num`.
+ T x = /*T & num*/ t;
+ x;
+ // Check that `T & Object` is a type of interest by promoting and then
+ // writing to it
+ if (x is int) {
+ /*T & int*/ x;
+ x = /*T & num*/ t;
+ /*T & Object*/ x;
+ }
+ }
+}
+
+localVariable_initialized_promoted_type_var_final<T>(T t) {
+ if (t is num) {
+ final x = /*T & num*/ t;
+ /*T & num*/ x;
+ // Note: it's not observable whether it's a type of interest because we
+ // can't write to it again.
+ }
+}
+
+localVariable_initialized_promoted_type_var_final_typed<T>(T t) {
+ if (t is num) {
+ final T x = /*T & num*/ t;
+ x;
+ // Note: it's not observable whether it's a type of interest because we
+ // can't write to it again.
+ }
}
localVariable_notDefinitelyUnassigned(bool a) {
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 8af47db..7514dc1 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- 1.29.0
+ 1.29.1
</h1>
<p>
This document contains a specification of the API provided by the
@@ -2267,6 +2267,13 @@
Return the set of fixes that are available for the errors at
a given offset in a given file.
</p>
+ <p>
+ If a request is made for a file which does not exist, or
+ which is not currently subject to analysis (e.g. because it
+ is not associated with any analysis root specified to
+ analysis.setAnalysisRoots), an error of type
+ <tt>GET_FIXES_INVALID_FILE</tt> will be generated.
+ </p>
<h4>parameters:</h4><dl><dt class="field"><b>file: <a href="#type_FilePath">FilePath</a></b></dt><dd>
@@ -5216,6 +5223,13 @@
which does not match a file currently subject to
analysis.
</p>
+ </dd><dt class="value">GET_FIXES_INVALID_FILE</dt><dd>
+
+ <p>
+ An "edit.getFixes" request specified a FilePath
+ which does not match a file currently subject to
+ analysis.
+ </p>
</dd><dt class="value">GET_IMPORTED_ELEMENTS_INVALID_FILE</dt><dd>
<p>
diff --git a/pkg/analysis_server/lib/protocol/protocol.dart b/pkg/analysis_server/lib/protocol/protocol.dart
index d45f7d3..53b008f 100644
--- a/pkg/analysis_server/lib/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/protocol/protocol.dart
@@ -366,6 +366,13 @@
'Error during `analysis.getErrors`: invalid file.'));
/// Initialize a newly created instance to represent the
+ /// GET_FIXES_INVALID_FILE error condition.
+ Response.getFixesInvalidFile(Request request)
+ : this(request.id,
+ error: RequestError(RequestErrorCode.GET_FIXES_INVALID_FILE,
+ 'Error during `edit.getFixes`: invalid file.'));
+
+ /// Initialize a newly created instance to represent the
/// GET_IMPORTED_ELEMENTS_INVALID_FILE error condition.
Response.getImportedElementsInvalidFile(Request request)
: this(request.id,
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 8bfb877..76c886f 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.29.0';
+const String PROTOCOL_VERSION = '1.29.1';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index 51ece87..06c3551 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -17810,6 +17810,7 @@
/// FORMAT_INVALID_FILE
/// FORMAT_WITH_ERRORS
/// GET_ERRORS_INVALID_FILE
+/// GET_FIXES_INVALID_FILE
/// GET_IMPORTED_ELEMENTS_INVALID_FILE
/// GET_KYTHE_ENTRIES_INVALID_FILE
/// GET_NAVIGATION_INVALID_FILE
@@ -17891,6 +17892,11 @@
static const RequestErrorCode GET_ERRORS_INVALID_FILE =
RequestErrorCode._('GET_ERRORS_INVALID_FILE');
+ /// An "edit.getFixes" request specified a FilePath which does not match a
+ /// file currently subject to analysis.
+ static const RequestErrorCode GET_FIXES_INVALID_FILE =
+ RequestErrorCode._('GET_FIXES_INVALID_FILE');
+
/// An "analysis.getImportedElements" request specified a FilePath that does
/// not match a file currently subject to analysis.
static const RequestErrorCode GET_IMPORTED_ELEMENTS_INVALID_FILE =
@@ -18022,6 +18028,7 @@
FORMAT_INVALID_FILE,
FORMAT_WITH_ERRORS,
GET_ERRORS_INVALID_FILE,
+ GET_FIXES_INVALID_FILE,
GET_IMPORTED_ELEMENTS_INVALID_FILE,
GET_KYTHE_ENTRIES_INVALID_FILE,
GET_NAVIGATION_INVALID_FILE,
@@ -18076,6 +18083,8 @@
return FORMAT_WITH_ERRORS;
case 'GET_ERRORS_INVALID_FILE':
return GET_ERRORS_INVALID_FILE;
+ case 'GET_FIXES_INVALID_FILE':
+ return GET_FIXES_INVALID_FILE;
case 'GET_IMPORTED_ELEMENTS_INVALID_FILE':
return GET_IMPORTED_ELEMENTS_INVALID_FILE;
case 'GET_KYTHE_ENTRIES_INVALID_FILE':
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 3e87f9c..2c9e1e4 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -639,9 +639,6 @@
/// ML completion is enabled if this is non-null.
String completionModelFolder;
- /// Whether to enable parsing via the Fasta parser.
- bool useFastaParser = true;
-
/// Return `true` if the new relevance computations should be used when
/// computing code completion suggestions.
bool useNewRelevance = true;
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index c56feb0..e18292c 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -162,7 +162,6 @@
sdkLanguageVersion: analyzer_features.ExperimentStatus.currentVersion,
flags: options.enabledExperiments,
);
- defaultContextOptions.useFastaParser = options.useFastaParser;
{
var name = options.newAnalysisDriverLog;
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 1254bc7..b09a113 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -747,11 +747,12 @@
void _analyzeDataFile(AnalysisDriver driver, String path) {
List<protocol.AnalysisError> convertedErrors;
try {
+ var file = resourceProvider.getFile(path);
+ var packageName = file.parent.parent.shortName;
var content = _readFile(path);
var errorListener = RecordingErrorListener();
- var errorReporter = ErrorReporter(
- errorListener, resourceProvider.getFile(path).createSource());
- var parser = TransformSetParser(errorReporter);
+ var errorReporter = ErrorReporter(errorListener, file.createSource());
+ var parser = TransformSetParser(errorReporter, packageName);
parser.parse(content);
var converter = AnalyzerConverter();
convertedErrors = converter.convertAnalysisErrors(errorListener.errors,
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 8ce7662..95ed5c8 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -280,6 +280,12 @@
if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
return;
}
+
+ if (!server.contextManager.isInAnalysisRoot(file)) {
+ server.sendResponse(Response.getFixesInvalidFile(request));
+ return;
+ }
+
//
// Allow plugins to start computing fixes.
//
diff --git a/pkg/analysis_server/lib/src/lsp/client_configuration.dart b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
index ebf42b7..55bfaf5 100644
--- a/pkg/analysis_server/lib/src/lsp/client_configuration.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
@@ -7,6 +7,19 @@
class LspClientConfiguration {
final Map<String, dynamic> _settings = <String, dynamic>{};
+ List<String> get analysisExcludedFolders {
+ // This setting is documented as a string array, but because editors are
+ // unlikely to provide validation, support single strings for convenience.
+ final value = _settings['analysisExcludedFolders'];
+ if (value is String) {
+ return [value];
+ } else if (value is List && value.every((s) => s is String)) {
+ return value.cast<String>();
+ } else {
+ return const [];
+ }
+ }
+
bool get enableSdkFormatter => _settings['enableSdkFormatter'] ?? true;
int get lineLength => _settings['lineLength'];
@@ -17,6 +30,13 @@
bool get previewCommitCharacters =>
_settings['previewCommitCharacters'] ?? false;
+ /// Returns whether or not the provided new configuration changes any values
+ /// that would require analysis roots to be updated.
+ bool affectsAnalysisRoots(Map<String, dynamic> newConfig) {
+ return _settings['analysisExcludedFolders'] !=
+ newConfig['analysisExcludedFolders'];
+ }
+
void replace(Map<String, dynamic> newConfig) {
_settings
..clear()
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 6fb0452..0e5a949 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -44,6 +44,11 @@
return success(const []);
}
+ final path = pathOfDoc(params.textDocument);
+ if (!path.isError && !server.isAnalyzedFile(path.result)) {
+ return success(const []);
+ }
+
final capabilities = server?.clientCapabilities?.textDocument;
final clientSupportsWorkspaceApplyEdit =
@@ -60,7 +65,6 @@
final clientSupportedDiagnosticTags = HashSet<DiagnosticTag>.of(
capabilities?.publishDiagnostics?.tagSupport?.valueSet ?? []);
- final path = pathOfDoc(params.textDocument);
final unit = await path.mapResult(requireResolvedUnit);
return unit.mapResult((unit) {
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 027f52e..32e92de 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -48,6 +48,7 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
+import 'package:path/path.dart';
import 'package:watcher/watcher.dart';
/// Instances of the class [LspAnalysisServer] implement an LSP-based server
@@ -218,7 +219,15 @@
result is List<dynamic> &&
result.length == 1 &&
result.first is Map<String, dynamic>) {
- clientConfiguration.replace(result.first);
+ final newConfig = result.first;
+ final refreshRoots =
+ clientConfiguration.affectsAnalysisRoots(newConfig);
+
+ clientConfiguration.replace(newConfig);
+
+ if (refreshRoots) {
+ _refreshAnalysisRoots();
+ }
}
}
@@ -320,6 +329,15 @@
}, socketError);
}
+ /// Returns `true` if the [file] with the given absolute path is included
+ /// in an analysis root and not excluded.
+ bool isAnalyzedFile(String file) {
+ return contextManager.isInAnalysisRoot(file) &&
+ // Dot folders are not analyzed (skipped over in _handleWatchEventImpl)
+ !contextManager.isContainedInDotFolder(file) &&
+ !contextManager.isIgnored(file);
+ }
+
/// Logs the error on the client using window/logMessage.
void logErrorToClient(String message) {
channel.sendNotification(NotificationMessage(
@@ -532,12 +550,7 @@
/// Returns `true` if errors should be reported for [file] with the given
/// absolute path.
bool shouldSendErrorsNotificationFor(String file) {
- // Errors should not be reported for things that are explicitly skipped
- // during normal analysis (for example dot folders are skipped over in
- // _handleWatchEventImpl).
- return contextManager.isInAnalysisRoot(file) &&
- !contextManager.isContainedInDotFolder(file) &&
- !contextManager.isIgnored(file);
+ return isAnalyzedFile(file);
}
/// Returns `true` if Flutter outlines should be sent for [file] with the
@@ -614,9 +627,19 @@
..addAll(_temporaryAnalysisRoots.values)
..toList();
+ final excludedPaths = clientConfiguration.analysisExcludedFolders
+ .expand((excludePath) => isAbsolute(excludePath)
+ ? [excludePath]
+ // Apply the relative path to each open workspace folder.
+ // TODO(dantup): Consider supporting per-workspace config by
+ // calling workspace/configuration whenever workspace folders change
+ // and caching the config for each one.
+ : _explicitAnalysisRoots.map((root) => join(root, excludePath)))
+ .toList();
+
declarationsTracker?.discardContexts();
- notificationManager.setAnalysisRoots(includedPaths.toList(), []);
- contextManager.setRoots(includedPaths.toList(), []);
+ notificationManager.setAnalysisRoots(includedPaths.toList(), excludedPaths);
+ contextManager.setRoots(includedPaths.toList(), excludedPaths);
addContextsToDeclarationsTracker();
}
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 44939fc..298fd30 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -110,6 +110,7 @@
void addOption(String name,
{String abbr,
String help,
+ String valueHelp,
List<String> allowed,
Map<String, String> allowedHelp,
String defaultsTo,
@@ -118,6 +119,7 @@
_parser.addOption(name,
abbr: abbr,
help: help,
+ valueHelp: valueHelp,
allowed: allowed,
allowedHelp: allowedHelp,
defaultsTo: defaultsTo,
@@ -276,9 +278,6 @@
/// The path to the data cache.
static const String CACHE_FOLDER = 'cache';
- /// Whether to enable parsing via the Fasta parser.
- static const String USE_FASTA_PARSER = 'use-fasta-parser';
-
/// The name of the flag to use the Language Server Protocol (LSP).
static const String USE_LSP = 'lsp';
@@ -341,7 +340,6 @@
analysisServerOptions.enabledExperiments =
(results[ENABLE_EXPERIMENT_OPTION] as List).cast<String>().toList();
}
- analysisServerOptions.useFastaParser = results[USE_FASTA_PARSER];
analysisServerOptions.useNewRelevance = results[USE_NEW_RELEVANCE];
// Read in any per-SDK overrides specified in <sdk>/config/settings.json.
@@ -747,9 +745,15 @@
/// Create and return the parser used to parse the command-line arguments.
CommandLineParser _createArgParser() {
var parser = CommandLineParser();
+ parser.addFlag(HELP_OPTION,
+ help: 'print this help message without starting a server',
+ abbr: 'h',
+ defaultsTo: false,
+ negatable: false);
parser.addOption(CLIENT_ID,
- help: 'an identifier used to identify the client');
- parser.addOption(CLIENT_VERSION, help: 'the version of the client');
+ valueHelp: 'name', help: 'an identifier used to identify the client');
+ parser.addOption(CLIENT_VERSION,
+ valueHelp: 'version', help: 'the version of the client');
parser.addFlag(DARTPAD_OPTION,
help: 'enable DartPad specific functionality',
defaultsTo: false,
@@ -774,18 +778,15 @@
help: 'enable sending instrumentation information to a server',
defaultsTo: false,
negatable: false);
- parser.addFlag(HELP_OPTION,
- help: 'print this help message without starting a server',
- abbr: 'h',
- defaultsTo: false,
- negatable: false);
parser.addOption(INSTRUMENTATION_LOG_FILE,
+ valueHelp: 'file path',
help: 'write instrumentation data to the given file');
parser.addFlag(INTERNAL_PRINT_TO_CONSOLE,
help: 'enable sending `print` output to the console',
defaultsTo: false,
negatable: false);
parser.addOption(NEW_ANALYSIS_DRIVER_LOG,
+ valueHelp: 'path',
help: "set a destination for the new analysis driver's log");
parser.addFlag(ANALYTICS_FLAG,
help: 'enable or disable sending analytics information to Google',
@@ -795,9 +796,11 @@
help: 'suppress analytics for this session',
hide: !telemetry.SHOW_ANALYTICS_UI);
parser.addOption(PORT_OPTION,
+ valueHelp: 'port',
help: 'the http diagnostic port on which the server provides'
' status and performance information');
- parser.addOption(SDK_OPTION, help: '[path] the path to the sdk');
+ parser.addOption(SDK_OPTION,
+ valueHelp: 'path', help: 'Path to the Dart sdk');
parser.addFlag(USE_ANALYSIS_HIGHLIGHT2,
help: 'enable version 2 of semantic highlight',
defaultsTo: false,
@@ -806,6 +809,7 @@
help: 'an option for reading files (some clients normalize eol '
'characters, which make the file offset and range information '
'incorrect)',
+ valueHelp: 'mode',
allowed: ['as-is', 'normalize-eol-always'],
allowedHelp: {
'as-is': 'file contents are read as-is',
@@ -814,21 +818,21 @@
},
defaultsTo: 'as-is');
parser.addOption(CACHE_FOLDER,
- help: '[path] path to the location where to cache data');
- parser.addFlag('preview-dart-2',
- help: 'Enable the Dart 2.0 preview (deprecated)', hide: true);
- parser.addFlag(USE_FASTA_PARSER,
- defaultsTo: true,
- help: 'Whether to enable parsing via the Fasta parser');
+ valueHelp: 'path', help: 'Path to the location to write cache data');
parser.addFlag(USE_LSP,
- defaultsTo: false, help: 'Whether to use the Language Server Protocol');
+ defaultsTo: false,
+ negatable: false,
+ help: 'Whether to use the Language Server Protocol');
parser.addFlag(ENABLE_COMPLETION_MODEL,
help: 'Whether or not to turn on ML ranking for code completion');
parser.addOption(COMPLETION_MODEL_FOLDER,
- help: '[path] path to the location of a code completion model');
+ valueHelp: 'path',
+ help: 'Path to the location of a code completion model');
parser.addOption(TRAIN_USING,
+ valueHelp: 'path',
help: 'Pass in a directory to analyze for purposes of training an '
'analysis server snapshot.');
+
//
// Temporary flags.
//
@@ -836,6 +840,12 @@
defaultsTo: true,
help: 'Use the new relevance computation for code completion.');
+ //
+ // Deprecated options - no longer read from.
+ //
+ parser.addFlag('use-fasta-parser', defaultsTo: true, hide: true);
+ parser.addFlag('preview-dart-2', hide: true);
+
return parser;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 357c58f..6f994e4 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -192,7 +192,8 @@
Future<void> compute(CorrectionProducer producer) async {
producer.configure(context);
- var builder = ChangeBuilder(workspace: context.workspace);
+ var builder = ChangeBuilder(
+ workspace: context.workspace, eol: context.utils.endOfLine);
await producer.compute(builder);
_addAssistFromBuilder(builder, producer.assistKind,
@@ -246,7 +247,8 @@
var producer = generator();
producer.configure(context);
- var builder = ChangeBuilder(workspace: context.workspace);
+ var builder = ChangeBuilder(
+ workspace: context.workspace, eol: context.utils.endOfLine);
await producer.compute(builder);
_addAssistFromBuilder(builder, producer.assistKind,
args: producer.assistArguments);
@@ -256,7 +258,8 @@
var multiProducer = multiGenerator();
multiProducer.configure(context);
for (var producer in multiProducer.producers) {
- var builder = ChangeBuilder(workspace: context.workspace);
+ var builder = ChangeBuilder(
+ workspace: context.workspace, eol: context.utils.endOfLine);
producer.configure(context);
await producer.compute(builder);
_addAssistFromBuilder(builder, producer.assistKind,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
index 7459fdb..d2c7fd5 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
@@ -32,7 +32,7 @@
return null;
}
var text = token.lexeme;
- var lines = text.split('\n');
+ var lines = text.split(eol);
var prefix = utils.getNodePrefix(comment);
var newLines = <String>[];
var firstLine = true;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart b/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
index bcf7198..234f33a 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
@@ -22,12 +22,16 @@
@override
Iterable<CorrectionProducer> get producers sync* {
var name = _name;
- var importedUris = <String>[];
+ var importedUris = <Uri>[];
var library = resolvedResult.libraryElement;
for (var importElement in library.imports) {
// TODO(brianwilkerson) Filter based on combinators to help avoid making
// invalid suggestions.
- importedUris.add(importElement.uri);
+ var uri = importElement.uri;
+ if (uri != null) {
+ // The [uri] is `null` if the literal string is not a valid URI.
+ importedUris.add(Uri.parse(uri));
+ }
}
for (var set in _availableTransformSetsForLibrary(library)) {
for (var transform in set.transformsFor(name, importedUris)) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
index 50ef9fe..936237a 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
@@ -101,44 +101,67 @@
void _applyToTypeArguments(
DartFileEditBuilder builder, DataDrivenFix fix, _TypeArgumentData data) {
+ var context = TemplateContext(fix.node, fix.utils);
var typeArguments = data.typeArguments;
- var argumentValueText = argumentValue.generate(fix.node, fix.utils);
if (typeArguments == null) {
// Adding the first type argument.
- builder.addSimpleInsertion(data.newListOffset, '<$argumentValueText>');
+ builder.addInsertion(data.newListOffset, (builder) {
+ builder.write('<');
+ argumentValue.writeOn(builder, context);
+ builder.write('>');
+ });
} else {
if (index == 0) {
// Inserting the type argument at the beginning of the list.
- builder.addSimpleInsertion(
- typeArguments.leftBracket.end, '$argumentValueText, ');
+ builder.addInsertion(typeArguments.leftBracket.end, (builder) {
+ argumentValue.writeOn(builder, context);
+ builder.write(', ');
+ });
} else {
// Inserting the type argument after an existing type argument.
var previous = typeArguments.arguments[index - 1];
- builder.addSimpleInsertion(previous.end, ', $argumentValueText');
+ builder.addInsertion(previous.end, (builder) {
+ builder.write(', ');
+ argumentValue.writeOn(builder, context);
+ });
}
}
}
void _applyToTypeParameters(
DartFileEditBuilder builder, DataDrivenFix fix, _TypeParameterData data) {
- var extendsClause = '';
- if (extendedType != null) {
- extendsClause = ' extends ${extendedType.generate(fix.node, fix.utils)}';
+ var context = TemplateContext(fix.node, fix.utils);
+
+ void writeParameter(DartEditBuilder builder) {
+ builder.write(name);
+ if (extendedType != null) {
+ builder.write(' extends ');
+ extendedType.writeOn(builder, context);
+ }
}
- var argumentValue = '$name$extendsClause';
+
var typeParameters = data.typeParameters;
if (typeParameters == null) {
// Adding the first type argument.
- builder.addSimpleInsertion(data.newListOffset, '<$argumentValue>');
+ builder.addInsertion(data.newListOffset, (builder) {
+ builder.write('<');
+ writeParameter(builder);
+ builder.write('>');
+ });
} else {
if (index == 0) {
// Inserting the type argument at the beginning of the list.
- builder.addSimpleInsertion(
- typeParameters.leftBracket.end, '$argumentValue, ');
+ builder.addInsertion(typeParameters.leftBracket.end, (builder) {
+ writeParameter(builder);
+ builder.write(', ');
+ });
} else {
// Inserting the type argument after an existing type argument.
var previous = typeParameters.typeParameters[index - 1];
- builder.addSimpleInsertion(previous.end, ', $argumentValue');
+ builder.addInsertion(previous.end, (builder) {
+ builder.write(', ');
+ writeParameter(builder);
+ });
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart
index 941d9be..cf17314 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
/// An object used to generate code to be inserted.
class CodeTemplate {
@@ -18,15 +19,6 @@
/// [components].
CodeTemplate(this.kind, this.components);
- String generate(AstNode node, CorrectionUtils utils) {
- var context = TemplateContext(node, utils);
- var buffer = StringBuffer();
- for (var component in components) {
- component.appendTo(buffer, context);
- }
- return buffer.toString();
- }
-
/// Use the [context] to validate that this template will be able to generate
/// a value.
bool validate(TemplateContext context) {
@@ -37,6 +29,12 @@
}
return true;
}
+
+ void writeOn(DartEditBuilder builder, TemplateContext context) {
+ for (var component in components) {
+ component.writeOn(builder, context);
+ }
+ }
}
/// The kinds of code that can be generated by a template.
@@ -47,14 +45,14 @@
/// An object used to compute some portion of a template.
abstract class TemplateComponent {
- /// Append the text contributed by this component to the given [sink], using
- /// the [context] to access needed information that isn't already known to
- /// this component.
- void appendTo(StringSink sink, TemplateContext context);
-
/// Use the [context] to validate that this component will be able to generate
/// a value.
bool validate(TemplateContext context);
+
+ /// Write the text contributed by this component to the given [builder], using
+ /// the [context] to access needed information that isn't already known to
+ /// this component.
+ void writeOn(DartEditBuilder builder, TemplateContext context);
}
/// The context in which a template is being evaluated.
@@ -65,20 +63,8 @@
/// The utilities used to help extract the code associated with various nodes.
final CorrectionUtils utils;
- /// A table mapping variable names to the values of those variables after they
- /// have been computed. Used to prevent computing the same value multiple
- /// times.
- final Map<ValueGenerator, String> _variableValues = {};
-
/// Initialize a newly created variable support.
TemplateContext(this.node, this.utils);
-
- /// Return the value of the variable with the given [name].
- String valueOf(ValueGenerator generator) {
- return _variableValues.putIfAbsent(generator, () {
- return generator.from(this);
- });
- }
}
/// Literal text within a template.
@@ -90,13 +76,13 @@
TemplateText(this.text);
@override
- void appendTo(StringSink sink, TemplateContext context) {
- sink.write(text);
+ bool validate(TemplateContext context) {
+ return true;
}
@override
- bool validate(TemplateContext context) {
- return true;
+ void writeOn(DartEditBuilder builder, TemplateContext context) {
+ builder.write(text);
}
}
@@ -109,12 +95,12 @@
TemplateVariable(this.generator);
@override
- void appendTo(StringSink sink, TemplateContext context) {
- sink.write(context.valueOf(generator));
+ bool validate(TemplateContext context) {
+ return generator.validate(context);
}
@override
- bool validate(TemplateContext context) {
- return generator.validate(context);
+ void writeOn(DartEditBuilder builder, TemplateContext context) {
+ generator.writeOn(builder, context);
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
index a0db646..1b25a68 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
@@ -7,7 +7,7 @@
/// The path to an element.
class ElementDescriptor {
/// The URIs of the library in which the element is defined.
- final List<String> libraryUris;
+ final List<Uri> libraryUris;
/// The kind of element that was changed.
final String _kind;
@@ -30,7 +30,7 @@
/// Return `true` if this descriptor matches an element with the given [name]
/// in a library that imports the [importedUris].
- bool matches(String name, List<String> importedUris) {
+ bool matches(String name, List<Uri> importedUris) {
var lastComponent = components.last;
if (lastComponent.isEmpty) {
if (components[components.length - 2] != name) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
index 857a509..3cd6143 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
@@ -91,12 +91,12 @@
/// Write to the [builder] the argument associated with a single
/// [parameter].
void writeArgument(DartEditBuilder builder, AddParameter parameter) {
- var value = parameter.argumentValue.generate(argumentList, fix.utils);
if (!parameter.isPositional) {
builder.write(parameter.name);
builder.write(': ');
}
- builder.write(value);
+ parameter.argumentValue
+ .writeOn(builder, TemplateContext(argumentList, fix.utils));
}
var insertionRanges = argumentsToInsert.contiguousSubRanges.toList();
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart
index ca9a24c..989b614 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart
@@ -31,7 +31,7 @@
/// Return `true` if this transform can be applied to fix an issue related to
/// an element with the given [name] in a library that imports the
/// [importedUris].
- bool appliesTo(String name, List<String> importedUris) {
+ bool appliesTo(String name, List<Uri> importedUris) {
return element.matches(name, importedUris);
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart
index e5c7445..5a966c6 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart
@@ -18,7 +18,7 @@
/// Return a list of the transforms that apply for a reference to the given
/// [name] in a library that imports the [importedUris].
- List<Transform> transformsFor(String name, List<String> importedUris) {
+ List<Transform> transformsFor(String name, List<Uri> importedUris) {
var result = <Transform>[];
for (var transform in _transforms) {
if (transform.appliesTo(name, importedUris)) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart
index 52cecbb..b477af8 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart
@@ -25,6 +25,9 @@
var workspace = library.session.analysisContext.workspace;
var libraryPath = library.source.fullName;
var package = workspace.findPackageFor(libraryPath);
+ if (package == null) {
+ return transformSets;
+ }
var packageMap = package.packagesAvailableTo(libraryPath);
for (var entry in packageMap.entries) {
var directory = entry.value[0];
@@ -45,8 +48,10 @@
try {
// TODO(brianwilkerson) Consider caching the transform sets.
var content = file.readAsStringSync();
- var parser = TransformSetParser(ErrorReporter(
- AnalysisErrorListener.NULL_LISTENER, file.createSource()));
+ var parser = TransformSetParser(
+ ErrorReporter(
+ AnalysisErrorListener.NULL_LISTENER, file.createSource()),
+ file.parent.parent.shortName);
return parser.parse(content);
} on FileSystemException {
// Fall through to return `null`.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index 1521f7c..96b3af0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -106,13 +106,15 @@
/// The error reporter to which diagnostics will be reported.
final ErrorReporter errorReporter;
+ final String packageName;
+
/// The parameter modifications associated with the current transform, or
/// `null` if the current transform does not yet have any such modifications.
List<ParameterModification> _parameterModifications;
/// Initialize a newly created parser to report diagnostics to the
/// [errorReporter].
- TransformSetParser(this.errorReporter);
+ TransformSetParser(this.errorReporter, this.packageName);
/// Return the result of parsing the file [content] into a transform set, or
/// `null` if the content does not represent a valid transform set.
@@ -466,7 +468,7 @@
ElementDescriptor _translateElement(YamlNode node, ErrorContext context) {
if (node is YamlMap) {
var uris = _translateList(node.valueAt(_urisKey),
- ErrorContext(key: _urisKey, parentNode: node), _translateString);
+ ErrorContext(key: _urisKey, parentNode: node), _translateUri);
var elementKey = _singleKey(node, const [
_classKey,
_constantKey,
@@ -526,7 +528,7 @@
ValueGenerator _translateImportValue(YamlMap node) {
_reportUnsupportedKeys(node, const {_kindKey, _nameKey, _urisKey});
var uris = _translateList(node.valueAt(_urisKey),
- ErrorContext(key: _urisKey, parentNode: node), _translateString);
+ ErrorContext(key: _urisKey, parentNode: node), _translateUri);
var name = _translateString(
node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
if (uris == null || name == null) {
@@ -752,6 +754,30 @@
}
}
+ /// Translate the [node] into a URI. Return the resulting URI, or `null` if
+ /// the [node] does not represent a valid URI. If the [node] is not valid, use
+ /// the [context] to report the error.
+ Uri _translateUri(YamlNode node, ErrorContext context,
+ {bool required = true}) {
+ if (node is YamlScalar) {
+ var value = node.value;
+ if (value is String) {
+ if (!(value.startsWith('dart:') || value.startsWith('package:'))) {
+ value = 'package:$packageName/$value';
+ }
+ return Uri.parse(value);
+ }
+ return _reportInvalidValue(node, context, 'URI');
+ } else if (node == null) {
+ if (required) {
+ return _reportMissingKey(context);
+ }
+ return null;
+ } else {
+ return _reportInvalidValue(node, context, 'URI');
+ }
+ }
+
/// Translate the [node] into a value extractor. Return the resulting
/// extractor, or `null` if the [node] does not represent a valid value
/// extractor. If the [node] is not valid, use the [context] to report the
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
index 43d83fc..1214e8b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
/// Use a specified argument from an invocation as the value of a template
/// variable.
@@ -19,18 +20,6 @@
ArgumentExpression(this.parameter) : assert(parameter != null);
@override
- String from(TemplateContext context) {
- var argumentList = _getArgumentList(context.node);
- if (argumentList != null) {
- var expression = parameter.argumentFrom(argumentList);
- if (expression != null) {
- return context.utils.getNodeText(expression);
- }
- }
- return null;
- }
-
- @override
bool validate(TemplateContext context) {
var argumentList = _getArgumentList(context.node);
if (argumentList == null) {
@@ -43,6 +32,17 @@
return true;
}
+ @override
+ void writeOn(DartEditBuilder builder, TemplateContext context) {
+ var argumentList = _getArgumentList(context.node);
+ if (argumentList != null) {
+ var expression = parameter.argumentFrom(argumentList);
+ if (expression != null) {
+ builder.write(context.utils.getNodeText(expression));
+ }
+ }
+ }
+
/// Return the argument list associated with the given [node].
ArgumentList _getArgumentList(AstNode node) {
if (node is ArgumentList) {
@@ -67,7 +67,7 @@
/// value of a template variable.
class ImportedName extends ValueGenerator {
/// The URIs of the libraries from which the name can be imported.
- final List<String> uris;
+ final List<Uri> uris;
/// The name to be used.
final String name;
@@ -75,25 +75,25 @@
ImportedName(this.uris, this.name);
@override
- String from(TemplateContext context) {
- // TODO(brianwilkerson) Figure out how to add the import when necessary.
- return name;
- }
-
- @override
bool validate(TemplateContext context) {
// TODO(brianwilkerson) Validate that the import can be added.
return true;
}
+
+ @override
+ void writeOn(DartEditBuilder builder, TemplateContext context) {
+ builder.writeImportedName(uris, name);
+ }
}
/// An object used to generate the value of a template variable.
abstract class ValueGenerator {
- /// Use the [context] to generate the value of a template variable and return
- /// the generated value.
- String from(TemplateContext context);
-
/// Use the [context] to validate that this generator will be able to generate
/// a value.
bool validate(TemplateContext context);
+
+ /// Write the value generated by this generator to the given [builder], using
+ /// the [context] to access needed information that isn't already known to
+ /// this generator.
+ void writeOn(DartEditBuilder builder, TemplateContext context);
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
index 58adedd5..09b73f8 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
@@ -141,7 +141,8 @@
@override
Future<SourceChange> createChange() async {
- var builder = ChangeBuilder(session: sessionHelper.session);
+ var builder =
+ ChangeBuilder(session: sessionHelper.session, eol: utils.endOfLine);
await builder.addDartFileEdit(resolveResult.path, (builder) {
if (_expression != null) {
builder.addReplacement(range.node(_expression), (builder) {
diff --git a/pkg/analysis_server/test/abstract_single_unit.dart b/pkg/analysis_server/test/abstract_single_unit.dart
index 5b10d92..d40c389 100644
--- a/pkg/analysis_server/test/abstract_single_unit.dart
+++ b/pkg/analysis_server/test/abstract_single_unit.dart
@@ -7,12 +7,14 @@
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/ast/element_locator.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/error/hint_codes.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/test_utilities/find_node.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:test/test.dart';
import 'abstract_context.dart';
@@ -20,6 +22,9 @@
class AbstractSingleUnitTest extends AbstractContextTest {
bool verifyNoTestUnitErrors = true;
+ /// Whether to rewrite line endings in test code based on platform.
+ bool useLineEndingsForPlatform = false;
+
String testCode;
String testFile;
Source testSource;
@@ -29,6 +34,14 @@
LibraryElement testLibraryElement;
FindNode findNode;
+ @override
+ Source addSource(String path, String content, [Uri uri]) {
+ if (useLineEndingsForPlatform) {
+ content = normalizeNewlinesForPlatform(content);
+ }
+ return super.addSource(path, content, uri);
+ }
+
void addTestSource(String code, [Uri uri]) {
testCode = code;
testSource = addSource(testFile, code, uri);
@@ -106,7 +119,18 @@
return length;
}
+ @override
+ File newFile(String path, {String content = ''}) {
+ if (useLineEndingsForPlatform) {
+ content = normalizeNewlinesForPlatform(content);
+ }
+ return super.newFile(path, content: content);
+ }
+
Future<void> resolveTestUnit(String code) async {
+ if (useLineEndingsForPlatform) {
+ code = normalizeNewlinesForPlatform(code);
+ }
addTestSource(code);
testAnalysisResult = await session.getResolvedUnit(testFile);
testUnit = testAnalysisResult.unit;
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 7de1b0d..19588f5 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -29,6 +29,24 @@
handler = EditDomainHandler(server);
}
+ Future<void> test_fileOutsideRoot() async {
+ final outsideFile = '/foo/test.dart';
+ newFile(outsideFile, content: 'bad code to create error');
+
+ // Set up the original project, as the code fix code won't run at all
+ // if there are no contexts.
+ createProject();
+ await waitForTasksFinished();
+
+ var request =
+ EditGetFixesParams(convertPath(outsideFile), 0).toRequest('0');
+ var response = await waitResponse(request);
+ expect(
+ response,
+ isResponseFailure('0', RequestErrorCode.GET_FIXES_INVALID_FILE),
+ );
+ }
+
Future<void> test_fixUndefinedClass() async {
createProject();
addTestFile('''
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index 9799790..c6f966e 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -1708,6 +1708,11 @@
/// Return the set of fixes that are available for the errors at a given
/// offset in a given file.
///
+ /// If a request is made for a file which does not exist, or which is not
+ /// currently subject to analysis (e.g. because it is not associated with any
+ /// analysis root specified to analysis.setAnalysisRoots), an error of type
+ /// GET_FIXES_INVALID_FILE will be generated.
+ ///
/// Parameters
///
/// file: FilePath
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index ffeed70..354c2aa 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1365,6 +1365,7 @@
/// FORMAT_INVALID_FILE
/// FORMAT_WITH_ERRORS
/// GET_ERRORS_INVALID_FILE
+/// GET_FIXES_INVALID_FILE
/// GET_IMPORTED_ELEMENTS_INVALID_FILE
/// GET_KYTHE_ENTRIES_INVALID_FILE
/// GET_NAVIGATION_INVALID_FILE
@@ -1401,6 +1402,7 @@
'FORMAT_INVALID_FILE',
'FORMAT_WITH_ERRORS',
'GET_ERRORS_INVALID_FILE',
+ 'GET_FIXES_INVALID_FILE',
'GET_IMPORTED_ELEMENTS_INVALID_FILE',
'GET_KYTHE_ENTRIES_INVALID_FILE',
'GET_NAVIGATION_INVALID_FILE',
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index ac4a575..0082910 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -195,4 +195,17 @@
applyChanges(contents, fixAction.edit.changes);
expect(contents[mainFilePath], equals(expectedContent));
}
+
+ Future<void> test_outsideRoot() async {
+ final otherFilePath = '/home/otherProject/foo.dart';
+ final otherFileUri = Uri.file(otherFilePath);
+ await newFile(otherFilePath, content: 'bad code to create error');
+ await initialize(
+ textDocumentCapabilities: withCodeActionKinds(
+ emptyTextDocumentClientCapabilities, [CodeActionKind.QuickFix]),
+ );
+
+ final codeActions = await getCodeActions(otherFileUri.toString());
+ expect(codeActions, isEmpty);
+ }
}
diff --git a/pkg/analysis_server/test/lsp/configuration_test.dart b/pkg/analysis_server/test/lsp/configuration_test.dart
index 16ea16e..0a864ee 100644
--- a/pkg/analysis_server/test/lsp/configuration_test.dart
+++ b/pkg/analysis_server/test/lsp/configuration_test.dart
@@ -48,6 +48,29 @@
expect(registration, isNull);
}
+ Future<void> test_configurationDidChange_refreshesRoots() async {
+ await provideConfig(
+ () => initialize(
+ workspaceCapabilities: withDidChangeConfigurationDynamicRegistration(
+ withConfigurationSupport(emptyWorkspaceClientCapabilities))),
+ {}, // Empty config
+ );
+
+ // Ensure the roots are as expected before we udpate the config.
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+ expect(server.contextManager.excludedPaths, isEmpty);
+
+ // Notify the server of updated config that includes an excluded path.
+ final excludedFolderPath = join(projectFolderPath, 'excluded');
+ await updateConfig({
+ 'analysisExcludedFolders': [excludedFolderPath]
+ });
+
+ // Ensure the roots were updated by the config change.
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+ expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+ }
+
Future<void> test_configurationDidChange_supported() async {
final registrations = <Registration>[];
await monitorDynamicRegistrations(
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index eeebebb..4bae1b9 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -331,6 +331,53 @@
expect(server.contextManager.includedPaths, equals([]));
}
+ Future<void> test_excludedFolders_absolute() async {
+ final excludedFolderPath = join(projectFolderPath, 'excluded');
+
+ await provideConfig(
+ () => initialize(
+ workspaceCapabilities:
+ withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+ // Exclude the folder with a relative path.
+ {
+ 'analysisExcludedFolders': [excludedFolderPath]
+ },
+ );
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+ expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+ }
+
+ Future<void> test_excludedFolders_nonList() async {
+ final excludedFolderPath = join(projectFolderPath, 'excluded');
+
+ await provideConfig(
+ () => initialize(
+ workspaceCapabilities:
+ withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+ // Include a single string instead of an array since it's an easy mistake
+ // to make without editor validation of settings.
+ {'analysisExcludedFolders': 'excluded'},
+ );
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+ expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+ }
+
+ Future<void> test_excludedFolders_relative() async {
+ final excludedFolderPath = join(projectFolderPath, 'excluded');
+
+ await provideConfig(
+ () => initialize(
+ workspaceCapabilities:
+ withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+ // Exclude the folder with a relative path.
+ {
+ 'analysisExcludedFolders': ['excluded']
+ },
+ );
+ expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+ expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+ }
+
Future<void> test_initialize() async {
final response = await initialize();
expect(response, isNotNull);
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index 1353f6d..9f40c52 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
show RefactoringProblemSeverity, SourceChange, SourceEdit;
import 'package:test/test.dart';
@@ -38,6 +39,9 @@
/// Asserts that [refactoringChange] contains a [FileEdit] for the file
/// with the given [path], and it results the [expectedCode].
void assertFileChangeResult(String path, String expectedCode) {
+ if (useLineEndingsForPlatform) {
+ expectedCode = normalizeNewlinesForPlatform(expectedCode);
+ }
// prepare FileEdit
var fileEdit = refactoringChange.getFileEdit(convertPath(path));
expect(fileEdit, isNotNull, reason: 'No file edit for $path');
@@ -112,6 +116,9 @@
/// Asserts that [refactoringChange] contains a [FileEdit] for [testFile], and
/// it results the [expectedCode].
void assertTestChangeResult(String expectedCode) {
+ if (useLineEndingsForPlatform) {
+ expectedCode = normalizeNewlinesForPlatform(expectedCode);
+ }
// prepare FileEdit
var fileEdit = refactoringChange.getFileEdit(testFile);
expect(fileEdit, isNotNull);
@@ -131,6 +138,8 @@
@override
void setUp() {
super.setUp();
+ // TODO(dantup): Get these tests passing with either line ending and change this to true.
+ useLineEndingsForPlatform = false;
searchEngine = SearchEngineImpl([driver]);
}
}
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index 5f53c00..9db1931 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -2923,7 +2923,8 @@
}
void _createRefactoringForStartEndComments() {
- var offset = findEnd('// start') + '\n'.length;
+ final eol = testCode.contains('\r\n') ? '\r\n' : '\r';
+ var offset = findEnd('// start') + eol.length;
var end = findOffset('// end');
_createRefactoring(offset, end - offset);
}
diff --git a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
index b25f74c..8c1da18 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
@@ -442,7 +442,7 @@
Widget build(BuildContext context) {
return createColumn();
}
-
+
Widget createColumn() {
var a = new Text('AAA');
var b = new Text('BBB');
@@ -499,7 +499,7 @@
],
);
}
-
+
Widget createColumn(String p1, int p2) {
var a = new Text('$foo $p1');
var b = new Text('$p2');
@@ -571,7 +571,7 @@
],
);
}
-
+
Widget createColumn({String p1, int p2}) {
var a = new Text('$foo $p1');
var b = new Text('$p2');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
index 3a9e20f..478f098 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/assist_internal.dart';
import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -53,6 +54,11 @@
/// have been applied.
Future<void> assertHasAssist(String expected,
{Map<String, List<String>> additionallyChangedFiles}) async {
+ if (useLineEndingsForPlatform) {
+ expected = normalizeNewlinesForPlatform(expected);
+ additionallyChangedFiles = additionallyChangedFiles?.map((key, value) =>
+ MapEntry(key, value.map(normalizeNewlinesForPlatform).toList()));
+ }
var assist = await _assertHasAssist();
_change = assist.change;
expect(_change.id, kind.id);
@@ -80,6 +86,9 @@
/// given [snippet] which produces the [expected] code when applied to [testCode].
Future<void> assertHasAssistAt(String snippet, String expected,
{int length = 0}) async {
+ if (useLineEndingsForPlatform) {
+ expected = normalizeNewlinesForPlatform(expected);
+ }
_offset = findOffset(snippet);
_length = length;
var assist = await _assertHasAssist();
@@ -134,6 +143,10 @@
@override
Future<void> resolveTestUnit(String code) async {
+ if (useLineEndingsForPlatform) {
+ code = normalizeNewlinesForPlatform(code);
+ }
+ final eol = code.contains('\r\n') ? '\r\n' : '\n';
var offset = code.indexOf('/*caret*/');
if (offset >= 0) {
var endOffset = offset + '/*caret*/'.length;
@@ -141,13 +154,13 @@
_offset = offset;
_length = 0;
} else {
- var startOffset = code.indexOf('// start\n');
- var endOffset = code.indexOf('// end\n');
+ var startOffset = code.indexOf('// start$eol');
+ var endOffset = code.indexOf('// end$eol');
if (startOffset >= 0 && endOffset >= 0) {
- var startLength = '// start\n'.length;
+ var startLength = '// start$eol'.length;
code = code.substring(0, startOffset) +
code.substring(startOffset + startLength, endOffset) +
- code.substring(endOffset + '// end\n'.length);
+ code.substring(endOffset + '// end$eol'.length);
_offset = startOffset;
_length = endOffset - startLength - _offset;
} else {
@@ -158,6 +171,12 @@
return super.resolveTestUnit(code);
}
+ @override
+ void setUp() {
+ super.setUp();
+ useLineEndingsForPlatform = true;
+ }
+
/// Computes assists and verifies that there is an assist of the given kind.
Future<Assist> _assertHasAssist() async {
var assists = await _computeAssists();
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
index b34b23d..f2db30e 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
@@ -19,6 +19,13 @@
@override
AssistKind get kind => DartAssistKind.FLUTTER_CONVERT_TO_CHILDREN;
+ @override
+ void setUp() {
+ super.setUp();
+ // TODO(dantup): Get these tests passing with either line ending.
+ useLineEndingsForPlatform = false;
+ }
+
Future<void> test_childUnresolved() async {
addFlutterPackage();
verifyNoTestUnitErrors = false;
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
index 794cc11..d53dda2 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
@@ -19,6 +19,13 @@
@override
AssistKind get kind => DartAssistKind.FLUTTER_WRAP_GENERIC;
+ @override
+ void setUp() {
+ super.setUp();
+ // TODO(dantup): Get these tests passing with either line ending.
+ useLineEndingsForPlatform = false;
+ }
+
Future<void> test_minimal() async {
addFlutterPackage();
await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart
index 3e17f59..c4268d2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart
@@ -19,6 +19,13 @@
@override
FixKind get kind => DartFixKind.CONVERT_FLUTTER_CHILD;
+ @override
+ void setUp() {
+ super.setUp();
+ // TODO(dantup): Get these tests passing with either line ending.
+ useLineEndingsForPlatform = false;
+ }
+
Future<void> test_hasList() async {
addFlutterPackage();
await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
index e9253d7..a57a686 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
@@ -20,6 +20,13 @@
@override
FixKind get kind => DartFixKind.CREATE_LOCAL_VARIABLE;
+ @override
+ void setUp() {
+ super.setUp();
+ // TODO(dantup): Get these tests passing with either line ending.
+ useLineEndingsForPlatform = false;
+ }
+
Future<void> test_functionType_named() async {
await resolveTestUnit('''
typedef MY_FUNCTION(int p);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart
index 5103e74..d397540 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -12,6 +13,7 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(CreateMissingOverridesTest);
+ defineReflectiveTests(CreateMissingOverridesWithNullSafetyTest);
});
}
@@ -197,34 +199,6 @@
''');
}
- Future<void> test_lineEndings() async {
- // TODO(dantup): Remove the need for this here, and have all of the tests
- // test with CRLF when running on Windows.
- final newlineWithoutCarriageReturn = RegExp(r'(?<!\r)\n');
- String asCrLf(String input) =>
- input.replaceAll(newlineWithoutCarriageReturn, '\r\n');
- await resolveTestUnit(asCrLf('''
-class A {
- void ma() {}
-}
-
-class B implements A {
-}
-'''));
- await assertHasFix(asCrLf('''
-class A {
- void ma() {}
-}
-
-class B implements A {
- @override
- void ma() {
- // TODO: implement ma
- }
-}
-'''));
- }
-
Future<void> test_mergeToField_getterSetter() async {
await resolveTestUnit('''
class A {
@@ -606,3 +580,58 @@
''');
}
}
+
+@reflectiveTest
+class CreateMissingOverridesWithNullSafetyTest extends FixProcessorTest {
+ @override
+ List<String> get experiments => [EnableString.non_nullable];
+
+ @override
+ FixKind get kind => DartFixKind.CREATE_MISSING_OVERRIDES;
+
+ Future<void> test_method_generic_nullable_dynamic() async {
+ // https://github.com/dart-lang/sdk/issues/43535
+ await resolveTestUnit('''
+class A {
+ void doSomething(Map<String, dynamic>? m) {}
+}
+
+class B implements A {}
+''');
+ await assertHasFix('''
+class A {
+ void doSomething(Map<String, dynamic>? m) {}
+}
+
+class B implements A {
+ @override
+ void doSomething(Map<String, dynamic>? m) {
+ // TODO: implement doSomething
+ }
+}
+''');
+ }
+
+ Future<void> test_method_generic_nullable_Never() async {
+ // https://github.com/dart-lang/sdk/issues/43535
+ await resolveTestUnit('''
+class A {
+ void doSomething(Map<String, Never>? m) {}
+}
+
+class B implements A {}
+''');
+ await assertHasFix('''
+class A {
+ void doSomething(Map<String, Never>? m) {}
+}
+
+class B implements A {
+ @override
+ void doSomething(Map<String, Never>? m) {
+ // TODO: implement doSomething
+ }
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
index e83eb02..c36b226 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
@@ -458,7 +458,7 @@
Transform(
title: 'title',
element: ElementDescriptor(
- libraryUris: [importUri],
+ libraryUris: [Uri.parse(importUri)],
// The kind isn't important to these tests.
kind: '',
components: components ?? ['C', 'm']),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
index 5713fb6..4802e4a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -76,7 +77,14 @@
var statement = body.block.statements[0] as ExpressionStatement;
var node = statement.expression;
var template = CodeTemplate(CodeTemplateKind.expression, components);
- var result = template.generate(node, CorrectionUtils(testAnalysisResult));
+ var builder = ChangeBuilder(session: session);
+ var context = TemplateContext(node, CorrectionUtils(testAnalysisResult));
+ await builder.addDartFileEdit(testFile, (builder) {
+ builder.addInsertion(0, (builder) {
+ template.writeOn(builder, context);
+ });
+ });
+ var result = builder.sourceChange.edits[0].edits[0].replacement;
expect(result, expectedResult);
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
index f0adabd..6d5e0aa 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
@@ -877,7 +877,7 @@
Transform(
title: 'title',
element: ElementDescriptor(
- libraryUris: [importUri],
+ libraryUris: [Uri.parse(importUri)],
// The kind isn't important to these tests.
kind: '',
components: originalComponents),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
index 4aff96a..0bd6479 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
@@ -1036,7 +1036,9 @@
Transform _rename(List<String> components, String newName) => Transform(
title: 'title',
element: ElementDescriptor(
- libraryUris: [importUri], kind: _kind, components: components),
+ libraryUris: [Uri.parse(importUri)],
+ kind: _kind,
+ components: components),
changes: [
Rename(newName: newName),
]);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
index 9e8c38a..45e1702 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -23,6 +23,8 @@
@reflectiveTest
class TransformSetParserTest extends AbstractTransformSetParserTest {
+ List<Uri> get uris => [Uri.parse('package:myPackage/test.dart')];
+
void test_addParameter_optionalNamed() {
parse('''
version: 1
@@ -44,7 +46,7 @@
kind: 'argument'
index: 1
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -80,7 +82,7 @@
name: 'p'
style: optional_positional
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -116,7 +118,7 @@
kind: 'argument'
index: 1
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -158,7 +160,7 @@
kind: 'argument'
index: 1
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -203,7 +205,7 @@
kind: 'argument'
index: 2
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -252,7 +254,7 @@
uris: ['dart:core']
name: 'String'
''');
- var transforms = result.transformsFor('A', ['test.dart']);
+ var transforms = result.transformsFor('A', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -263,7 +265,7 @@
var components = change.argumentValue.components;
expect(components, hasLength(1));
var value = (components[0] as TemplateVariable).generator as ImportedName;
- expect(value.uris, ['dart:core']);
+ expect(value.uris, [Uri.parse('dart:core')]);
expect(value.name, 'String');
}
@@ -288,7 +290,7 @@
kind: 'argument'
name: 'p'
''');
- var transforms = result.transformsFor('A', ['test.dart']);
+ var transforms = result.transformsFor('A', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -329,7 +331,7 @@
kind: 'argument'
index: 2
''');
- var transforms = result.transformsFor('A', ['test.dart']);
+ var transforms = result.transformsFor('A', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Add');
@@ -361,7 +363,7 @@
getter: 'g'
changes: []
''');
- var transforms = result.transformsFor('g', ['test.dart']);
+ var transforms = result.transformsFor('g', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Rename g');
@@ -380,7 +382,7 @@
inMixin: 'A'
changes: []
''');
- var transforms = result.transformsFor('g', ['test.dart']);
+ var transforms = result.transformsFor('g', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Rename g');
@@ -398,7 +400,7 @@
getter: 'g'
changes: []
''');
- var transforms = result.transformsFor('g', ['test.dart']);
+ var transforms = result.transformsFor('g', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Rename g');
@@ -417,7 +419,7 @@
inClass: 'A'
changes: []
''');
- var transforms = result.transformsFor('m', ['test.dart']);
+ var transforms = result.transformsFor('m', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Rename m');
@@ -458,7 +460,7 @@
- kind: 'removeParameter'
name: 'p'
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Remove');
@@ -484,7 +486,7 @@
- kind: 'removeParameter'
index: 0
''');
- var transforms = result.transformsFor('f', ['test.dart']);
+ var transforms = result.transformsFor('f', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Remove');
@@ -511,7 +513,7 @@
- kind: 'rename'
newName: 'B'
''');
- var transforms = result.transformsFor('A', ['test.dart']);
+ var transforms = result.transformsFor('A', uris);
expect(transforms, hasLength(1));
var transform = transforms[0];
expect(transform.title, 'Rename A');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
index 1fa4200..789ef46 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
@@ -37,7 +37,7 @@
void parse(String content) {
errorListener = GatheringErrorListener();
var errorReporter = ErrorReporter(errorListener, MockSource('data.yaml'));
- var parser = TransformSetParser(errorReporter);
+ var parser = TransformSetParser(errorReporter, 'myPackage');
result = parser.parse(content);
}
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index f5d7d59..a7fb58c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
import 'package:analyzer/src/services/available_declarations.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError;
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
@@ -86,6 +87,9 @@
String target,
int expectedNumberOfFixesForKind,
String matchFixMessage}) async {
+ if (useLineEndingsForPlatform) {
+ expected = normalizeNewlinesForPlatform(expected);
+ }
var error = await _findErrorToFix(errorFilter, length: length);
var fix = await _assertHasFix(error,
expectedNumberOfFixesForKind: expectedNumberOfFixesForKind,
@@ -108,6 +112,9 @@
void assertHasFixAllFix(ErrorCode errorCode, String expected,
{String target}) async {
+ if (useLineEndingsForPlatform) {
+ expected = normalizeNewlinesForPlatform(expected);
+ }
var error = await _findErrorToFixOfType(errorCode);
var fix = await _assertHasFixAllFix(error);
change = fix.change;
@@ -169,6 +176,7 @@
void setUp() {
super.setUp();
verifyNoTestUnitErrors = false;
+ useLineEndingsForPlatform = true;
_createAnalysisOptionsFile();
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
index f3f154c..f54560f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
@@ -20,6 +20,13 @@
@override
FixKind get kind => DartFixKind.REMOVE_UNUSED_IMPORT;
+ @override
+ void setUp() {
+ super.setUp();
+ // TODO(dantup): Get these tests passing with either line ending.
+ useLineEndingsForPlatform = false;
+ }
+
Future<void> test_all_diverseImports() async {
await resolveTestUnit('''
import 'dart:math';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart
index 3d8e7ef..f35360f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart
@@ -63,7 +63,7 @@
class C {
C(int b = 1,);
}
-''', errorFilter: (e) => e.offset == 14);
+''', errorFilter: (e) => e.offset == testCode.indexOf('int a'));
}
Future<void> test_first_requiredPositional_second_optionalNamed() async {
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index ee2d987..f3f3dd1 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -574,6 +574,10 @@
*
* Return the set of fixes that are available for the errors at a given offset in a given file.
*
+ * If a request is made for a file which does not exist, or which is not currently subject to
+ * analysis (e.g. because it is not associated with any analysis root specified to
+ * analysis.setAnalysisRoots), an error of type GET_FIXES_INVALID_FILE will be generated.
+ *
* @param file The file containing the errors for which fixes are being requested.
* @param offset The offset used to select the errors for which fixes will be returned.
*/
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index 0129bac..44da4d7 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -77,6 +77,12 @@
public static final String GET_ERRORS_INVALID_FILE = "GET_ERRORS_INVALID_FILE";
/**
+ * An "edit.getFixes" request specified a FilePath which does not match a file currently subject to
+ * analysis.
+ */
+ public static final String GET_FIXES_INVALID_FILE = "GET_FIXES_INVALID_FILE";
+
+ /**
* An "analysis.getImportedElements" request specified a FilePath that does not match a file
* currently subject to analysis.
*/
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 0247bb1..6bcf904 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- <version>1.29.0</version>
+ <version>1.29.1</version>
</h1>
<p>
This document contains a specification of the API provided by the
@@ -2345,6 +2345,13 @@
Return the set of fixes that are available for the errors at
a given offset in a given file.
</p>
+ <p>
+ If a request is made for a file which does not exist, or
+ which is not currently subject to analysis (e.g. because it
+ is not associated with any analysis root specified to
+ analysis.setAnalysisRoots), an error of type
+ <tt>GET_FIXES_INVALID_FILE</tt> will be generated.
+ </p>
<params>
<field name="file">
<ref>FilePath</ref>
@@ -5004,6 +5011,14 @@
</p>
</value>
<value>
+ <code>GET_FIXES_INVALID_FILE</code>
+ <p>
+ An "edit.getFixes" request specified a FilePath
+ which does not match a file currently subject to
+ analysis.
+ </p>
+ </value>
+ <value>
<code>GET_IMPORTED_ELEMENTS_INVALID_FILE</code>
<p>
An "analysis.getImportedElements" request specified a FilePath that
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 8bfb877..76c886f 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.29.0';
+const String PROTOCOL_VERSION = '1.29.1';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 29ae9ac..b6d697f 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -17810,6 +17810,7 @@
/// FORMAT_INVALID_FILE
/// FORMAT_WITH_ERRORS
/// GET_ERRORS_INVALID_FILE
+/// GET_FIXES_INVALID_FILE
/// GET_IMPORTED_ELEMENTS_INVALID_FILE
/// GET_KYTHE_ENTRIES_INVALID_FILE
/// GET_NAVIGATION_INVALID_FILE
@@ -17891,6 +17892,11 @@
static const RequestErrorCode GET_ERRORS_INVALID_FILE =
RequestErrorCode._('GET_ERRORS_INVALID_FILE');
+ /// An "edit.getFixes" request specified a FilePath which does not match a
+ /// file currently subject to analysis.
+ static const RequestErrorCode GET_FIXES_INVALID_FILE =
+ RequestErrorCode._('GET_FIXES_INVALID_FILE');
+
/// An "analysis.getImportedElements" request specified a FilePath that does
/// not match a file currently subject to analysis.
static const RequestErrorCode GET_IMPORTED_ELEMENTS_INVALID_FILE =
@@ -18022,6 +18028,7 @@
FORMAT_INVALID_FILE,
FORMAT_WITH_ERRORS,
GET_ERRORS_INVALID_FILE,
+ GET_FIXES_INVALID_FILE,
GET_IMPORTED_ELEMENTS_INVALID_FILE,
GET_KYTHE_ENTRIES_INVALID_FILE,
GET_NAVIGATION_INVALID_FILE,
@@ -18076,6 +18083,8 @@
return FORMAT_WITH_ERRORS;
case 'GET_ERRORS_INVALID_FILE':
return GET_ERRORS_INVALID_FILE;
+ case 'GET_FIXES_INVALID_FILE':
+ return GET_FIXES_INVALID_FILE;
case 'GET_IMPORTED_ELEMENTS_INVALID_FILE':
return GET_IMPORTED_ELEMENTS_INVALID_FILE;
case 'GET_KYTHE_ENTRIES_INVALID_FILE':
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 9312ea8..e65f60b 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -514,6 +514,7 @@
HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
HintCode.INVALID_SEALED_ANNOTATION,
+ HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index 74f160b..9f390a8 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -8,7 +8,7 @@
/// The current version of the Dart language (or, for non-stable releases, the
/// version of the language currently in the process of being developed).
-const _currentVersion = '2.10.0';
+const _currentVersion = '2.11.0';
/// A map containing information about all known experimental flags.
final _knownFeatures = <String, ExperimentalFeature>{
diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart
index fa08358..d04ddfa 100644
--- a/pkg/analyzer/lib/src/dart/element/scope.dart
+++ b/pkg/analyzer/lib/src/dart/element/scope.dart
@@ -184,12 +184,16 @@
final Map<String, Element> _getters = {};
final Map<String, Element> _setters = {};
final Set<ExtensionElement> _extensions = {};
+ LibraryElement _deferredLibrary;
PrefixScope(this._library, PrefixElement prefix) {
for (var import in _library.imports) {
if (import.prefix == prefix) {
var elements = impl.NamespaceBuilder().getImportedElements(import);
elements.forEach(_add);
+ if (import.isDeferred) {
+ _deferredLibrary ??= import.importedLibrary;
+ }
}
}
}
@@ -203,6 +207,10 @@
@override
ScopeLookupResult lookup2(String id) {
+ if (_deferredLibrary != null && id == FunctionElement.LOAD_LIBRARY_NAME) {
+ return ScopeLookupResult(_deferredLibrary.loadLibraryFunction, null);
+ }
+
var getter = _getters[id];
var setter = _setters[id];
return ScopeLookupResult(getter, setter);
diff --git a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
index 21cdd9c..c3040b2 100644
--- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -139,8 +139,19 @@
// If `Q` is a legacy type `Q0*` then the match holds under constraint
// set `C`:
- // Only if `P` is a subtype match for `Q?` under constraint set `C`.
if (Q_nullability == NullabilitySuffix.star) {
+ // If `P` is `dynamic` or `void` and `P` is a subtype match
+ // for `Q0` under constraint set `C`.
+ if (identical(P, DynamicTypeImpl.instance) ||
+ identical(P, VoidTypeImpl.instance)) {
+ var rewind = _constraints.length;
+ var Q0 = (Q as TypeImpl).withNullability(NullabilitySuffix.none);
+ if (trySubtypeMatch(P, Q0, leftSchema)) {
+ return true;
+ }
+ _constraints.length = rewind;
+ }
+ // Or if `P` is a subtype match for `Q0?` under constraint set `C`.
var Qq = (Q as TypeImpl).withNullability(NullabilitySuffix.question);
return trySubtypeMatch(P, Qq, leftSchema);
}
@@ -201,6 +212,16 @@
_constraints.length = rewind;
}
+ // Or if `P` is `dynamic` or `void` and `Object` is a subtype match
+ // for `Q0` under constraint set `C`.
+ if (identical(P, DynamicTypeImpl.instance) ||
+ identical(P, VoidTypeImpl.instance)) {
+ if (trySubtypeMatch(_typeSystem.objectNone, Q0, leftSchema)) {
+ return true;
+ }
+ _constraints.length = rewind;
+ }
+
// Or if `P` is a subtype match for `Q0` under non-empty
// constraint set `C`.
var P_matches_Q0 = trySubtypeMatch(P, Q0, leftSchema);
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 9be0aa2..fb65bd2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -943,6 +943,17 @@
correction: "Remove @sealed.");
/**
+ * This hint is generated anywhere where a member annotated with `@internal`
+ * is used outside of the package in which it is declared.
+ *
+ * Parameters:
+ * 0: the name of the member
+ */
+ static const HintCode INVALID_USE_OF_INTERNAL_MEMBER = HintCode(
+ 'INVALID_USE_OF_INTERNAL_MEMBER',
+ "The member '{0}' can only be used within its package.");
+
+ /**
* This hint is generated anywhere where a member annotated with `@protected`
* is used outside of an instance member of a subclass.
*
diff --git a/pkg/analyzer/lib/src/dart/micro/libraries_log.dart b/pkg/analyzer/lib/src/dart/micro/libraries_log.dart
new file mode 100644
index 0000000..a67988b
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/micro/libraries_log.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2020, 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:meta/meta.dart';
+
+class ChangeFileLoadEntry extends LibrariesLogEntry {
+ /// The path of the file that was reported as changed.
+ final String target;
+
+ /// The files that depend transitively on the [target]. These files are
+ /// removed from the state, and from the element factory.
+ final List<LibrariesLogFile> removed = [];
+
+ ChangeFileLoadEntry._(this.target);
+
+ void addRemoved({
+ @required String path,
+ @required Uri uri,
+ }) {
+ removed.add(
+ LibrariesLogFile._(path, uri),
+ );
+ }
+
+ @override
+ String toString() {
+ return 'Change(target: $target, removed: $removed)';
+ }
+}
+
+class LibrariesLog {
+ final List<LibrariesLogEntry> entries = [];
+
+ ChangeFileLoadEntry changeFile(String path) {
+ var entry = ChangeFileLoadEntry._(path);
+ entries.add(entry);
+ return entry;
+ }
+
+ LoadLibrariesForTargetLogEntry loadForTarget({
+ @required String path,
+ @required Uri uri,
+ }) {
+ var entry = LoadLibrariesForTargetLogEntry._(
+ LibrariesLogFile._(path, uri),
+ );
+ entries.add(entry);
+ return entry;
+ }
+}
+
+abstract class LibrariesLogEntry {
+ final DateTime time = DateTime.now();
+}
+
+class LibrariesLogFile {
+ final String path;
+ final Uri uri;
+
+ LibrariesLogFile._(this.path, this.uri);
+
+ @override
+ String toString() {
+ return '(path: $path, uri: $uri)';
+ }
+}
+
+class LoadLibrariesForTargetLogEntry extends LibrariesLogEntry {
+ final LibrariesLogFile target;
+ final List<LibrariesLogFile> loaded = [];
+
+ LoadLibrariesForTargetLogEntry._(this.target);
+
+ void addLibrary({
+ @required String path,
+ @required Uri uri,
+ }) {
+ loaded.add(
+ LibrariesLogFile._(path, uri),
+ );
+ }
+
+ @override
+ String toString() {
+ return 'Load(target: $target, loaded: $loaded)';
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 7d07bcf..206d69c 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -20,8 +20,10 @@
import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/micro/analysis_context.dart';
import 'package:analyzer/src/dart/micro/cider_byte_store.dart';
+import 'package:analyzer/src/dart/micro/libraries_log.dart';
import 'package:analyzer/src/dart/micro/library_analyzer.dart';
import 'package:analyzer/src/dart/micro/library_graph.dart';
+import 'package:analyzer/src/exception/exception.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisEngine, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart';
@@ -73,6 +75,8 @@
MicroContextObjects contextObjects;
+ final LibrariesLog _librariesLog = LibrariesLog();
+
_LibraryContext libraryContext;
FileResolver(
@@ -117,6 +121,10 @@
);
}
+ List<LibrariesLogEntry> get librariesLogEntries {
+ return _librariesLog.entries;
+ }
+
/// Update the resolver to reflect the fact that the file with the given
/// [path] was changed. We need to make sure that when this file, of any file
/// that directly or indirectly referenced it, is resolved, we used the new
@@ -130,6 +138,15 @@
var removedFiles = <FileState>[];
fsState.changeFile(path, removedFiles);
+ // Update the log.
+ var logEntry = _librariesLog.changeFile(path);
+ for (var removedFile in removedFiles) {
+ logEntry.addRemoved(
+ path: removedFile.path,
+ uri: removedFile.uri,
+ );
+ }
+
// Remove libraries represented by removed files.
// If we need these libraries later, we will relink and reattach them.
if (libraryContext != null) {
@@ -307,15 +324,28 @@
(file) => file.getContentWithSameDigest(),
);
- results = performance.run('analyze', (performance) {
- return NullSafetyUnderstandingFlag.enableNullSafetyTypes(() {
- return libraryAnalyzer.analyzeSync(
- completionPath: completionOffset != null ? path : null,
- completionOffset: completionOffset,
- performance: performance,
- );
+ try {
+ results = performance.run('analyze', (performance) {
+ return NullSafetyUnderstandingFlag.enableNullSafetyTypes(() {
+ return libraryAnalyzer.analyzeSync(
+ completionPath: completionOffset != null ? path : null,
+ completionOffset: completionOffset,
+ performance: performance,
+ );
+ });
});
- });
+ } catch (exception, stackTrace) {
+ var fileContentMap = <String, String>{};
+ for (var file in libraryFile.libraryFiles) {
+ var path = file.path;
+ fileContentMap[path] = _getFileContent(path);
+ }
+ throw CaughtExceptionWithFiles(
+ exception,
+ stackTrace,
+ fileContentMap,
+ );
+ }
});
UnitAnalysisResult fileResult = results[file];
@@ -398,6 +428,7 @@
resourceProvider,
byteStore,
contextObjects,
+ _librariesLog,
);
}
}
@@ -539,6 +570,7 @@
final ResourceProvider resourceProvider;
final CiderByteStore byteStore;
final MicroContextObjects contextObjects;
+ final LibrariesLog librariesLog;
LinkedElementFactory elementFactory;
@@ -549,6 +581,7 @@
this.resourceProvider,
this.byteStore,
this.contextObjects,
+ this.librariesLog,
) {
// TODO(scheglov) remove it?
_createElementFactory();
@@ -565,9 +598,21 @@
var librariesLinkedTimer = Stopwatch();
var inputsTimer = Stopwatch();
+ var logEntry = librariesLog.loadForTarget(
+ path: targetLibrary.path,
+ uri: targetLibrary.uri,
+ );
+
void loadBundle(LibraryCycle cycle) {
if (!loadedBundles.add(cycle)) return;
+ for (var library in cycle.libraries) {
+ logEntry.addLibrary(
+ path: library.path,
+ uri: library.uri,
+ );
+ }
+
performance.getDataInt('cycleCount').increment();
performance.getDataInt('libraryCount').add(cycle.libraries.length);
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
new file mode 100644
index 0000000..92fef68
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -0,0 +1,343 @@
+// Copyright (c) 2020, 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/constant/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+class AnnotationResolver {
+ final ResolverVisitor _resolver;
+
+ AnnotationResolver(this._resolver);
+
+ LibraryElement get _definingLibrary => _resolver.definingLibrary;
+
+ ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+ void resolve(Annotation node) {
+ AstNode parent = node.parent;
+
+ _resolve1(node);
+
+ node.constructorName?.accept(_resolver);
+ Element element = node.element;
+ if (element is ExecutableElement) {
+ InferenceContext.setType(node.arguments, element.type);
+ }
+ node.arguments?.accept(_resolver);
+
+ ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation;
+ if (elementAnnotationImpl == null) {
+ // Analyzer ignores annotations on "part of" directives.
+ assert(parent is PartOfDirective);
+ } else {
+ elementAnnotationImpl.annotationAst = _createCloner().cloneNode(node);
+ }
+ }
+
+ /// Return a newly created cloner that can be used to clone constant
+ /// expressions.
+ ///
+ /// TODO(scheglov) this is duplicate
+ ConstantAstCloner _createCloner() {
+ return ConstantAstCloner();
+ }
+
+ InterfaceType _instantiateAnnotationClass(ClassElement element) {
+ return element.instantiate(
+ typeArguments: List.filled(
+ element.typeParameters.length,
+ DynamicTypeImpl.instance,
+ ),
+ nullabilitySuffix: _resolver.noneOrStarSuffix,
+ );
+ }
+
+ void _resolve1(Annotation node) {
+ var nodeName = node.name;
+
+ if (nodeName is PrefixedIdentifier) {
+ var prefix = nodeName.prefix;
+ var identifier = nodeName.identifier;
+
+ prefix.accept(_resolver);
+ var prefixElement = prefix.staticElement;
+
+ if (prefixElement is ClassElement && node.arguments != null) {
+ var element = prefixElement.getNamedConstructor(identifier.name);
+ element = _resolver.toLegacyElement(element);
+
+ identifier.staticElement = element;
+ identifier.staticType = element?.type ?? DynamicTypeImpl.instance;
+ // TODO(scheglov) error?
+ } else if (prefixElement is PrefixElement) {
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolvePrefixedIdentifier(
+ node: nodeName,
+ hasRead: true,
+ hasWrite: false,
+ forAnnotation: true,
+ );
+
+ var element = result.readElement;
+ identifier.staticElement = element;
+
+ if (element == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_ANNOTATION,
+ node,
+ [identifier.name],
+ );
+ }
+ } else {
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolvePrefixedIdentifier(
+ node: nodeName,
+ hasRead: true,
+ hasWrite: false,
+ forAnnotation: true,
+ );
+
+ var element = result.readElement;
+ identifier.staticElement = element;
+
+ DartType type;
+ if (element is PropertyAccessorElement && element.isGetter) {
+ type = element.returnType;
+ } else {
+ type = DynamicTypeImpl.instance;
+ }
+ identifier.staticType = type;
+ }
+ } else {
+ var identifier = nodeName as SimpleIdentifier;
+
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolveSimpleIdentifier(
+ node: identifier,
+ hasRead: true,
+ hasWrite: false,
+ );
+
+ var element = result.readElement;
+ identifier.staticElement = element;
+
+ if (element == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_ANNOTATION,
+ node,
+ [identifier.name],
+ );
+ }
+
+ DartType type;
+ if (element is ClassElement) {
+ type = _resolver.typeProvider.typeType;
+ } else if (element is PropertyAccessorElement && element.isGetter) {
+ type = element.returnType;
+ } else {
+ type = DynamicTypeImpl.instance;
+ }
+ identifier.staticType = type;
+ }
+
+ _resolveAnnotationElement(node);
+ }
+
+ void _resolveAnnotationConstructorInvocationArguments(
+ Annotation annotation, ConstructorElement constructor) {
+ ArgumentList argumentList = annotation.arguments;
+ // error will be reported in ConstantVerifier
+ if (argumentList == null) {
+ return;
+ }
+ // resolve arguments to parameters
+ List<ParameterElement> parameters =
+ _resolveArgumentsToFunction(argumentList, constructor);
+ if (parameters != null) {
+ argumentList.correspondingStaticParameters = parameters;
+ }
+ }
+
+ /// Continues resolution of the given [annotation].
+ void _resolveAnnotationElement(Annotation annotation) {
+ SimpleIdentifier nameNode1;
+ SimpleIdentifier nameNode2;
+ {
+ Identifier annName = annotation.name;
+ if (annName is PrefixedIdentifier) {
+ nameNode1 = annName.prefix;
+ nameNode2 = annName.identifier;
+ } else {
+ nameNode1 = annName as SimpleIdentifier;
+ nameNode2 = null;
+ }
+ }
+ SimpleIdentifier nameNode3 = annotation.constructorName;
+ ConstructorElement constructor;
+ bool undefined = false;
+ //
+ // CONST or Class(args)
+ //
+ if (nameNode1 != null && nameNode2 == null && nameNode3 == null) {
+ Element element1 = nameNode1.staticElement;
+ // TODO(scheglov) Must be const.
+ if (element1 is VariableElement) {
+ return;
+ }
+ // CONST
+ if (element1 is PropertyAccessorElement) {
+ _resolveAnnotationElementGetter(annotation, element1);
+ return;
+ }
+ // Class(args)
+ if (element1 is ClassElement) {
+ constructor = _instantiateAnnotationClass(element1)
+ .lookUpConstructor(null, _definingLibrary);
+ constructor = _resolver.toLegacyElement(constructor);
+ } else if (element1 == null) {
+ undefined = true;
+ }
+ }
+ //
+ // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args)
+ //
+ if (nameNode1 != null && nameNode2 != null && nameNode3 == null) {
+ Element element1 = nameNode1.staticElement;
+ Element element2 = nameNode2.staticElement;
+ // Class.CONST - not resolved yet
+ if (element1 is ClassElement) {
+ element2 = element1.lookUpGetter(nameNode2.name, _definingLibrary);
+ element2 = _resolver.toLegacyElement(element2);
+ }
+ // prefix.CONST or Class.CONST
+ if (element2 is PropertyAccessorElement) {
+ nameNode2.staticElement = element2;
+ annotation.element = element2;
+ _resolveAnnotationElementGetter(annotation, element2);
+ return;
+ }
+ // prefix.Class()
+ if (element2 is ClassElement) {
+ constructor = element2.unnamedConstructor;
+ constructor = _resolver.toLegacyElement(constructor);
+ }
+ // Class.constructor(args)
+ if (element1 is ClassElement) {
+ constructor = _instantiateAnnotationClass(element1)
+ .lookUpConstructor(nameNode2.name, _definingLibrary);
+ constructor = _resolver.toLegacyElement(constructor);
+ nameNode2.staticElement = constructor;
+ }
+ if (element1 is PrefixElement && element2 == null) {
+ undefined = true;
+ }
+ if (element1 == null && element2 == null) {
+ undefined = true;
+ }
+ }
+ //
+ // prefix.Class.CONST or prefix.Class.constructor(args)
+ //
+ if (nameNode1 != null && nameNode2 != null && nameNode3 != null) {
+ Element element2 = nameNode2.staticElement;
+ // element2 should be ClassElement
+ if (element2 is ClassElement) {
+ String name3 = nameNode3.name;
+ // prefix.Class.CONST
+ PropertyAccessorElement getter =
+ element2.lookUpGetter(name3, _definingLibrary);
+ if (getter != null) {
+ getter = _resolver.toLegacyElement(getter);
+ nameNode3.staticElement = getter;
+ annotation.element = getter;
+ _resolveAnnotationElementGetter(annotation, getter);
+ return;
+ }
+ // prefix.Class.constructor(args)
+ constructor = _instantiateAnnotationClass(element2)
+ .lookUpConstructor(name3, _definingLibrary);
+ constructor = _resolver.toLegacyElement(constructor);
+ nameNode3.staticElement = constructor;
+ } else if (element2 == null) {
+ undefined = true;
+ }
+ }
+ // we need constructor
+ if (constructor == null) {
+ if (!undefined) {
+ // If the class was not found then we've already reported the error.
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+ }
+ return;
+ }
+ // record element
+ annotation.element = constructor;
+ // resolve arguments
+ _resolveAnnotationConstructorInvocationArguments(annotation, constructor);
+ }
+
+ void _resolveAnnotationElementGetter(
+ Annotation annotation, PropertyAccessorElement accessorElement) {
+ // accessor should be synthetic
+ if (!accessorElement.isSynthetic) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION_GETTER, annotation);
+ return;
+ }
+ // variable should be constant
+ VariableElement variableElement = accessorElement.variable;
+ if (!variableElement.isConst) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+ return;
+ }
+ // no arguments
+ if (annotation.arguments != null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ANNOTATION_WITH_NON_CLASS,
+ annotation.name,
+ [annotation.name]);
+ }
+ // OK
+ return;
+ }
+
+ /// Given an [argumentList] and the [executableElement] that will be invoked
+ /// using those argument, compute the list of parameters that correspond to
+ /// the list of arguments. An error will be reported if any of the arguments
+ /// cannot be matched to a parameter. Return the parameters that correspond to
+ /// the arguments, or `null` if no correspondence could be computed.
+ ///
+ /// TODO(scheglov) this is duplicate
+ List<ParameterElement> _resolveArgumentsToFunction(
+ ArgumentList argumentList, ExecutableElement executableElement) {
+ if (executableElement == null) {
+ return null;
+ }
+ List<ParameterElement> parameters = executableElement.parameters;
+ return _resolveArgumentsToParameters(argumentList, parameters);
+ }
+
+ /// Given an [argumentList] and the [parameters] related to the element that
+ /// will be invoked using those arguments, compute the list of parameters that
+ /// correspond to the list of arguments. An error will be reported if any of
+ /// the arguments cannot be matched to a parameter. Return the parameters that
+ /// correspond to the arguments.
+ ///
+ /// TODO(scheglov) this is duplicate
+ List<ParameterElement> _resolveArgumentsToParameters(
+ ArgumentList argumentList, List<ParameterElement> parameters) {
+ return ResolverVisitor.resolveArgumentsToParameters(
+ argumentList, parameters, _errorReporter.reportErrorForNode);
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 0190caa..59d39ff 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -10,16 +10,12 @@
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/token.dart';
-import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
-import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
-import 'package:analyzer/src/error/assignment_verifier.dart';
import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/migration.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:meta/meta.dart';
@@ -47,52 +43,66 @@
bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
- MigrationResolutionHooks get _migrationResolutionHooks {
- return _resolver.migrationResolutionHooks;
- }
-
TypeProvider get _typeProvider => _resolver.typeProvider;
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
void resolve(AssignmentExpressionImpl node) {
+ var operator = node.operator.type;
+ var hasRead = operator != TokenType.EQ;
+ var isIfNull = operator == TokenType.QUESTION_QUESTION_EQ;
+
+ var leftResolution = _resolver.resolveForWrite(
+ node: node.leftHandSide,
+ hasRead: hasRead,
+ );
+
var left = node.leftHandSide;
var right = node.rightHandSide;
- if (left is IndexExpression) {
- _resolve_IndexExpression(node, left);
- return;
+ var readElement = leftResolution.readElement;
+ var writeElement = leftResolution.writeElement;
+
+ if (hasRead) {
+ _resolver.setReadElement(left, readElement);
+ }
+ _resolver.setWriteElement(left, writeElement);
+
+ _resolver.setAssignmentBackwardCompatibility(
+ assignment: node,
+ left: left,
+ hasRead: hasRead,
+ );
+
+ _resolveOperator(node);
+
+ {
+ var leftType = node.writeType;
+ if (writeElement is VariableElement) {
+ leftType = _resolver.localVariableTypeProvider.getType(left);
+ }
+ _setRhsContext(node, leftType, operator, right);
}
- if (left is PrefixedIdentifier) {
- _resolve_PrefixedIdentifier(node, left);
- return;
+ var flow = _flowAnalysis?.flow;
+ if (flow != null && isIfNull) {
+ flow.ifNullExpression_rightBegin(left, node.readType);
}
- if (left is PropertyAccess) {
- _resolve_PropertyAccess(node, left);
- return;
- }
+ right.accept(_resolver);
- if (left is SimpleIdentifier) {
- _resolve_SimpleIdentifier(node, left);
- return;
- }
+ _resolveTypes(node);
- left?.accept(_resolver);
- left = node.leftHandSide;
-
- var operator = node.operator.type;
- if (operator != TokenType.EQ) {
- if (node.readElement == null || node.readType == null) {
- _resolver.setReadElement(left, null);
+ if (flow != null) {
+ if (writeElement is VariableElement) {
+ flow.write(writeElement, node.staticType);
+ }
+ if (isIfNull) {
+ flow.ifNullExpression_end();
}
}
- if (node.writeElement == null || node.writeType == null) {
- _resolver.setWriteElement(left, null);
- }
- _resolve3(node, left, operator, right);
+ _resolver.nullShortingTermination(node);
}
void _checkForInvalidAssignment(
@@ -139,30 +149,8 @@
return true;
}
- /// Record that the static type of the given node is the given type.
- ///
- /// @param expression the node whose type is to be recorded
- /// @param type the static type of the node
- ///
- /// TODO(scheglov) this is duplication
- void _recordStaticType(Expression expression, DartType type) {
- if (_resolver.migrationResolutionHooks != null) {
- type = _migrationResolutionHooks.modifyExpressionType(expression, type);
- }
-
- // TODO(scheglov) type cannot be null
- if (type == null) {
- expression.staticType = DynamicTypeImpl.instance;
- } else {
- expression.staticType = type;
- if (_typeSystem.isBottom(type)) {
- _flowAnalysis?.flow?.handleExit();
- }
- }
- }
-
- void _resolve1(AssignmentExpressionImpl node) {
- var leftHandSide = node.leftHandSide;
+ void _resolveOperator(AssignmentExpressionImpl node) {
+ var left = node.leftHandSide;
var operator = node.operator;
var operatorType = operator.type;
@@ -171,7 +159,8 @@
return;
}
- _assignmentShared.checkFinalAlreadyAssigned(leftHandSide);
+ // TODO(scheglov) Use VariableElement and do in resolveForWrite() ?
+ _assignmentShared.checkFinalAlreadyAssigned(left);
// Values of the type void cannot be used.
// Example: `y += 0`, is not allowed.
@@ -196,10 +185,10 @@
var methodName = binaryOperatorType.lexeme;
var result = _typePropertyResolver.resolve(
- receiver: leftHandSide,
+ receiver: left,
receiverType: leftType,
name: methodName,
- receiverErrorNode: leftHandSide,
+ receiverErrorNode: left,
nameErrorEntity: operator,
);
node.staticElement = result.getter;
@@ -212,170 +201,6 @@
}
}
- void _resolve3(AssignmentExpressionImpl node, Expression left,
- TokenType operator, Expression right) {
- _resolve1(node);
-
- {
- var leftType = node.writeType;
- if (node.writeElement is VariableElement) {
- leftType = _resolver.localVariableTypeProvider.getType(left);
- }
- _setRhsContext(node, leftType, operator, right);
- }
-
- var flow = _flowAnalysis?.flow;
- if (flow != null && operator == TokenType.QUESTION_QUESTION_EQ) {
- flow.ifNullExpression_rightBegin(left, node.readType);
- }
-
- right?.accept(_resolver);
- right = node.rightHandSide;
-
- _resolveTypes(node);
-
- _resolver.nullShortingTermination(node);
-
- if (flow != null) {
- if (node.writeElement is VariableElement) {
- flow.write(node.writeElement, node.staticType);
- }
- if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
- flow.ifNullExpression_end();
- }
- }
- }
-
- void _resolve_IndexExpression(
- AssignmentExpressionImpl node,
- IndexExpression left,
- ) {
- left.target?.accept(_resolver);
- _resolver.startNullAwareIndexExpression(left);
-
- var operator = node.operator.type;
- var hasRead = operator != TokenType.EQ;
-
- var resolver = PropertyElementResolver(_resolver);
- var result = resolver.resolveIndexExpression(
- node: left,
- hasRead: hasRead,
- hasWrite: true,
- );
-
- var readElement = result.readElement;
- var writeElement = result.writeElement;
-
- InferenceContext.setType(left.index, result.indexContextType);
- left.index.accept(_resolver);
-
- if (hasRead) {
- _resolver.setReadElement(left, readElement);
- }
- _resolver.setWriteElement(left, writeElement);
-
- _setBackwardCompatibility(node);
-
- var right = node.rightHandSide;
- _resolve3(node, left, operator, right);
- }
-
- void _resolve_PrefixedIdentifier(
- AssignmentExpressionImpl node,
- PrefixedIdentifier left,
- ) {
- left.prefix?.accept(_resolver);
-
- var operator = node.operator.type;
- var hasRead = operator != TokenType.EQ;
-
- var resolver = PropertyElementResolver(_resolver);
- var result = resolver.resolvePrefixedIdentifier(
- node: left,
- hasRead: hasRead,
- hasWrite: true,
- );
-
- var readElement = result.readElement;
- var writeElement = result.writeElement;
-
- if (hasRead) {
- _resolver.setReadElement(left, readElement);
- }
- _resolver.setWriteElement(left, writeElement);
-
- _setBackwardCompatibility(node);
-
- var right = node.rightHandSide;
- _resolve3(node, left, operator, right);
- }
-
- void _resolve_PropertyAccess(
- AssignmentExpressionImpl node,
- PropertyAccess left,
- ) {
- left.target?.accept(_resolver);
-
- var operator = node.operator.type;
- var hasRead = operator != TokenType.EQ;
-
- _resolver.startNullAwarePropertyAccess(left);
-
- var resolver = PropertyElementResolver(_resolver);
- var result = resolver.resolvePropertyAccess(
- node: left,
- hasRead: hasRead,
- hasWrite: true,
- );
-
- var readElement = result.readElement;
- var writeElement = result.writeElement;
-
- if (hasRead) {
- _resolver.setReadElement(left, readElement);
- }
- _resolver.setWriteElement(left, writeElement);
-
- _setBackwardCompatibility(node);
-
- var right = node.rightHandSide;
- _resolve3(node, left, operator, right);
- }
-
- void _resolve_SimpleIdentifier(
- AssignmentExpressionImpl node,
- SimpleIdentifier left,
- ) {
- var right = node.rightHandSide;
- var operator = node.operator.type;
-
- if (operator != TokenType.EQ) {
- var readLookup = _resolver.lexicalLookup(node: left, setter: false);
- var readElement = readLookup.requested;
- _resolver.setReadElement(left, readElement);
- }
-
- var writeLookup = _resolver.lexicalLookup(node: left, setter: true);
- var writeElement = writeLookup.requested ?? writeLookup.recovery;
- _resolver.setWriteElement(left, writeElement);
-
- AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
- node: left,
- requested: writeLookup.requested,
- recovery: writeLookup.recovery,
- receiverTypeObject: null,
- );
-
- _setBackwardCompatibility(node);
-
- if (operator != TokenType.EQ) {
- // TODO(scheglov) Change this method to work with elements.
- _resolver.checkReadOfNotAssignedLocalVariable(left);
- }
-
- _resolve3(node, left, operator, right);
- }
-
void _resolveTypes(AssignmentExpressionImpl node) {
DartType assignedType;
DartType nodeType;
@@ -426,56 +251,6 @@
);
}
- /// TODO(scheglov) This is mostly necessary for backward compatibility.
- /// Although we also use `staticElement` for `getType(left)` below.
- void _setBackwardCompatibility(AssignmentExpressionImpl node) {
- var operator = node.operator.type;
-
- var left = node.leftHandSide;
- var hasRead = operator != TokenType.EQ;
-
- if (left is IndexExpression) {
- if (hasRead) {
- left.staticElement = node.writeElement;
- left.auxiliaryElements = AuxiliaryElements(node.readElement);
- _resolver.setReadElement(node, node.readElement);
- _resolver.setWriteElement(node, node.writeElement);
- } else {
- left.staticElement = node.writeElement;
- _resolver.setWriteElement(node, node.writeElement);
- }
- _recordStaticType(left, node.writeType);
- return;
- }
-
- SimpleIdentifier leftIdentifier;
- if (left is PrefixedIdentifier) {
- leftIdentifier = left.identifier;
- _recordStaticType(left, node.writeType);
- } else if (left is PropertyAccess) {
- leftIdentifier = left.propertyName;
- _recordStaticType(left, node.writeType);
- } else if (left is SimpleIdentifier) {
- leftIdentifier = left;
- }
-
- if (hasRead) {
- var readElement = node.readElement;
- if (readElement is PropertyAccessorElement) {
- leftIdentifier.auxiliaryElements = AuxiliaryElements(readElement);
- }
- }
-
- leftIdentifier.staticElement = node.writeElement;
- if (node.readElement is VariableElement) {
- var leftType =
- _resolver.localVariableTypeProvider.getType(leftIdentifier);
- _recordStaticType(leftIdentifier, leftType);
- } else {
- _recordStaticType(leftIdentifier, node.writeType);
- }
- }
-
void _setRhsContext(AssignmentExpressionImpl node, DartType leftType,
TokenType operator, Expression right) {
switch (operator) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index be06c78..4455cf3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -341,13 +341,6 @@
}
@override
- bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
- return variable is LocalVariableElement &&
- variable.hasImplicitType &&
- !variable.hasInitializer;
- }
-
- @override
bool isNever(DartType type) {
return typeSystem.isBottom(type);
}
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 2329df1..c22c1e4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -196,6 +196,31 @@
return false;
}
+ /// Given an uninstantiated generic function type, referenced by the
+ /// [identifier] in the tear-off [expression], try to infer the instantiated
+ /// generic function type from the surrounding context.
+ DartType inferTearOff(
+ Expression expression,
+ SimpleIdentifier identifier,
+ DartType tearOffType,
+ ) {
+ var context = InferenceContext.getContext(expression);
+ if (context is FunctionType && tearOffType is FunctionType) {
+ var typeArguments = _typeSystem.inferFunctionTypeInstantiation(
+ context,
+ tearOffType,
+ errorReporter: _resolver.errorReporter,
+ errorNode: expression,
+ );
+ (identifier as SimpleIdentifierImpl).tearOffTypeArgumentTypes =
+ typeArguments;
+ if (typeArguments.isNotEmpty) {
+ return tearOffType.instantiate(typeArguments);
+ }
+ }
+ return tearOffType;
+ }
+
/// Record that the static type of the given node is the given type.
///
/// @param expression the node whose type is to be recorded
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 e8c0531..951bde7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -475,8 +475,6 @@
void _resolveReceiverNull(
MethodInvocation node, SimpleIdentifier nameNode, String name) {
- _resolver.checkReadOfNotAssignedLocalVariable(nameNode);
-
var element = nameScope.lookup2(name).getter;
if (element != null) {
element = _resolver.toLegacyElement(element);
@@ -492,6 +490,7 @@
return _setResolution(node, element.type);
}
if (element is VariableElement) {
+ _resolver.checkReadOfNotAssignedLocalVariable(nameNode, element);
var targetType = _localVariableTypeProvider.getType(nameNode);
return _rewriteAsFunctionExpressionInvocation(node, targetType);
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index bcebac1..75d46e2 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -52,26 +52,26 @@
return;
}
- node.operand.accept(_resolver);
+ var operandResolution = _resolver.resolveForWrite(
+ node: node.operand,
+ hasRead: true,
+ );
+
+ var readElement = operandResolution.readElement;
+ var writeElement = operandResolution.writeElement;
var operand = node.operand;
- if (operand is SimpleIdentifier) {
- var element = operand.staticElement;
- // ElementResolver does not set it.
- if (element is VariableElement) {
- _resolver.setReadElement(operand, element);
- _resolver.setWriteElement(operand, element);
- }
- }
+ _resolver.setReadElement(operand, readElement);
+ _resolver.setWriteElement(operand, writeElement);
- if (node.readElement == null || node.readType == null) {
- _resolver.setReadElement(operand, null);
- }
- if (node.writeElement == null || node.writeType == null) {
- _resolver.setWriteElement(operand, null);
- }
+ _resolver.setAssignmentBackwardCompatibility(
+ assignment: node,
+ left: operand,
+ hasRead: true,
+ );
- _assignmentShared.checkFinalAlreadyAssigned(node.operand);
+ // TODO(scheglov) Use VariableElement and do in resolveForWrite() ?
+ _assignmentShared.checkFinalAlreadyAssigned(operand);
var receiverType = node.readType;
_resolve1(node, receiverType);
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 76cde43..62142f1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -49,32 +49,34 @@
void resolve(PrefixExpressionImpl node) {
var operator = node.operator.type;
+
if (operator == TokenType.BANG) {
_resolveNegation(node);
return;
}
- node.operand.accept(_resolver);
-
- var operand = node.operand;
- if (operand is SimpleIdentifier) {
- var element = operand.staticElement;
- // ElementResolver does not set it.
- if (element is VariableElement) {
- _resolver.setReadElement(operand, element);
- _resolver.setWriteElement(operand, element);
- }
- }
-
- if (node.readElement == null || node.readType == null) {
- _resolver.setReadElement(operand, null);
- }
- if (node.writeElement == null || node.writeType == null) {
- _resolver.setWriteElement(operand, null);
- }
-
if (operator.isIncrementOperator) {
+ var operandResolution = _resolver.resolveForWrite(
+ node: node.operand,
+ hasRead: true,
+ );
+
+ var readElement = operandResolution.readElement;
+ var writeElement = operandResolution.writeElement;
+
+ var operand = node.operand;
+ _resolver.setReadElement(operand, readElement);
+ _resolver.setWriteElement(operand, writeElement);
+
+ _resolver.setAssignmentBackwardCompatibility(
+ assignment: node,
+ left: operand,
+ hasRead: true,
+ );
+
_assignmentShared.checkFinalAlreadyAssigned(node.operand);
+ } else {
+ node.operand.accept(_resolver);
}
_resolve1(node);
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
new file mode 100644
index 0000000..54a67e4
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
@@ -0,0 +1,194 @@
+// Copyright (c) 2020, 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+class PrefixedIdentifierResolver {
+ final ResolverVisitor _resolver;
+
+ PrefixedIdentifierResolver(this._resolver);
+
+ InvocationInferenceHelper get _inferenceHelper => _resolver.inferenceHelper;
+
+ TypeProviderImpl get _typeProvider => _resolver.typeProvider;
+
+ void resolve(PrefixedIdentifier node) {
+ node.prefix.accept(_resolver);
+
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolvePrefixedIdentifier(
+ node: node,
+ hasRead: true,
+ hasWrite: false,
+ );
+
+ var identifier = node.identifier;
+ identifier.staticElement = result.readElement;
+
+ _resolve2(node);
+ }
+
+ /// Return the type that should be recorded for a node that resolved to the given accessor.
+ ///
+ /// @param accessor the accessor that the node resolved to
+ /// @return the type that should be recorded for a node that resolved to the given accessor
+ ///
+ /// TODO(scheglov) this is duplicate
+ DartType _getTypeOfProperty(PropertyAccessorElement accessor) {
+ FunctionType functionType = accessor.type;
+ if (functionType == null) {
+ // TODO(brianwilkerson) Report this internal error. This happens when we
+ // are analyzing a reference to a property before we have analyzed the
+ // declaration of the property or when the property does not have a
+ // defined type.
+ return DynamicTypeImpl.instance;
+ }
+ if (accessor.isSetter) {
+ List<DartType> parameterTypes = functionType.normalParameterTypes;
+ if (parameterTypes != null && parameterTypes.isNotEmpty) {
+ return parameterTypes[0];
+ }
+ PropertyAccessorElement getter = accessor.variable.getter;
+ if (getter != null) {
+ functionType = getter.type;
+ if (functionType != null) {
+ return functionType.returnType;
+ }
+ }
+ return DynamicTypeImpl.instance;
+ }
+ return functionType.returnType;
+ }
+
+ /// Return `true` if the given [node] is not a type literal.
+ ///
+ /// TODO(scheglov) this is duplicate
+ bool _isExpressionIdentifier(Identifier node) {
+ var parent = node.parent;
+ if (node is SimpleIdentifier && node.inDeclarationContext()) {
+ return false;
+ }
+ if (parent is ConstructorDeclaration) {
+ if (parent.name == node || parent.returnType == node) {
+ return false;
+ }
+ }
+ if (parent is ConstructorName ||
+ parent is MethodInvocation ||
+ parent is PrefixedIdentifier && parent.prefix == node ||
+ parent is PropertyAccess ||
+ parent is TypeName) {
+ return false;
+ }
+ return true;
+ }
+
+ /// Record that the static type of the given node is the given type.
+ ///
+ /// @param expression the node whose type is to be recorded
+ /// @param type the static type of the node
+ ///
+ /// TODO(scheglov) this is duplicate
+ void _recordStaticType(Expression expression, DartType type) {
+ _inferenceHelper.recordStaticType(expression, type);
+ }
+
+ void _resolve2(PrefixedIdentifier node) {
+ SimpleIdentifier prefixedIdentifier = node.identifier;
+ Element staticElement = prefixedIdentifier.staticElement;
+
+ if (staticElement is ExtensionElement) {
+ _setExtensionIdentifierType(node);
+ return;
+ }
+
+ if (identical(node.prefix.staticType, NeverTypeImpl.instance)) {
+ _recordStaticType(prefixedIdentifier, NeverTypeImpl.instance);
+ _recordStaticType(node, NeverTypeImpl.instance);
+ return;
+ }
+
+ DartType staticType = DynamicTypeImpl.instance;
+ if (staticElement is ClassElement) {
+ if (_isExpressionIdentifier(node)) {
+ var type = _typeProvider.typeType;
+ node.staticType = type;
+ node.identifier.staticType = type;
+ }
+ return;
+ } else if (staticElement is DynamicElementImpl) {
+ var type = _typeProvider.typeType;
+ node.staticType = type;
+ node.identifier.staticType = type;
+ return;
+ } else if (staticElement is FunctionTypeAliasElement) {
+ if (node.parent is TypeName) {
+ // no type
+ } else {
+ var type = _typeProvider.typeType;
+ node.staticType = type;
+ node.identifier.staticType = type;
+ }
+ return;
+ } else if (staticElement is MethodElement) {
+ staticType = staticElement.type;
+ } else if (staticElement is PropertyAccessorElement) {
+ staticType = _getTypeOfProperty(staticElement);
+ } else if (staticElement is ExecutableElement) {
+ staticType = staticElement.type;
+ } else if (staticElement is VariableElement) {
+ staticType = staticElement.type;
+ }
+
+ staticType =
+ _inferenceHelper.inferTearOff(node, node.identifier, staticType);
+
+ _recordStaticType(prefixedIdentifier, staticType);
+ _recordStaticType(node, staticType);
+ }
+
+ /// TODO(scheglov) this is duplicate
+ void _setExtensionIdentifierType(Identifier node) {
+ if (node is SimpleIdentifier && node.inDeclarationContext()) {
+ return;
+ }
+
+ var parent = node.parent;
+
+ if (parent is PrefixedIdentifier && parent.identifier == node) {
+ node = parent;
+ parent = node.parent;
+ }
+
+ if (parent is CommentReference ||
+ parent is ExtensionOverride && parent.extensionName == node ||
+ parent is MethodInvocation && parent.target == node ||
+ parent is PrefixedIdentifier && parent.prefix == node ||
+ parent is PropertyAccess && parent.target == node) {
+ return;
+ }
+
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
+ node,
+ [node.name],
+ );
+
+ if (node is PrefixedIdentifier) {
+ node.identifier.staticType = DynamicTypeImpl.instance;
+ node.staticType = DynamicTypeImpl.instance;
+ } else if (node is SimpleIdentifier) {
+ node.staticType = DynamicTypeImpl.instance;
+ }
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index b3ed076..08ce229 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/error/assignment_verifier.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -125,30 +126,19 @@
@required PrefixedIdentifier node,
@required bool hasRead,
@required bool hasWrite,
+ bool forAnnotation = false,
}) {
var prefix = node.prefix;
var identifier = node.identifier;
var prefixElement = prefix.staticElement;
if (prefixElement is PrefixElement) {
- var lookupResult = prefixElement.scope.lookup2(identifier.name);
-
- var readElement = _resolver.toLegacyElement(lookupResult.getter);
- var writeElement = _resolver.toLegacyElement(lookupResult.setter);
-
- if (hasRead && readElement == null || hasWrite && writeElement == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
- identifier,
- [identifier.name, prefixElement.name],
- );
- }
-
- return PropertyElementResolverResult(
- readElementRequested: readElement,
- readElementRecovery: null,
- writeElementRequested: writeElement,
- writeElementRecovery: null,
+ return _resolveTargetPrefixElement(
+ target: prefixElement,
+ identifier: identifier,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ forAnnotation: forAnnotation,
);
}
@@ -198,6 +188,42 @@
);
}
+ PropertyElementResolverResult resolveSimpleIdentifier({
+ @required SimpleIdentifier node,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ Element readElementRequested;
+ Element readElementRecovery;
+ if (hasRead) {
+ var readLookup = _resolver.lexicalLookup(node: node, setter: false);
+ readElementRequested = readLookup.requested;
+ _resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested);
+ }
+
+ Element writeElementRequested;
+ Element writeElementRecovery;
+ if (hasWrite) {
+ var writeLookup = _resolver.lexicalLookup(node: node, setter: true);
+ writeElementRequested = writeLookup.requested;
+ writeElementRecovery = writeLookup.recovery;
+
+ AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
+ node: node,
+ requested: writeElementRequested,
+ recovery: writeElementRecovery,
+ receiverTypeObject: null,
+ );
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: readElementRequested,
+ readElementRecovery: readElementRecovery,
+ writeElementRequested: writeElementRequested,
+ writeElementRecovery: writeElementRecovery,
+ );
+ }
+
void _checkExtensionOverrideStaticMember(
SimpleIdentifier propertyName,
ExecutableElement element,
@@ -515,6 +541,40 @@
);
}
+ PropertyElementResolverResult _resolveTargetPrefixElement({
+ @required PrefixElement target,
+ @required SimpleIdentifier identifier,
+ @required bool hasRead,
+ @required bool hasWrite,
+ @required bool forAnnotation,
+ }) {
+ var lookupResult = target.scope.lookup2(identifier.name);
+
+ var readElement = _resolver.toLegacyElement(lookupResult.getter);
+ var writeElement = _resolver.toLegacyElement(lookupResult.setter);
+
+ if (hasRead && readElement == null || hasWrite && writeElement == null) {
+ if (!forAnnotation &&
+ !_resolver.nameScope.shouldIgnoreUndefined2(
+ prefix: target.name,
+ name: identifier.name,
+ )) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
+ identifier,
+ [identifier.name, target.name],
+ );
+ }
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: readElement,
+ readElementRecovery: null,
+ writeElementRequested: writeElement,
+ writeElementRecovery: null,
+ );
+ }
+
PropertyElementResolverResult _resolveTargetSuperExpression({
@required SuperExpression target,
@required SimpleIdentifier propertyName,
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 5d65e55..05b73cc 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -97,8 +97,8 @@
_strictInference =
(analysisOptions as AnalysisOptionsImpl).strictInference,
_inheritanceManager = inheritanceManager,
- _invalidAccessVerifier =
- _InvalidAccessVerifier(_errorReporter, _currentLibrary),
+ _invalidAccessVerifier = _InvalidAccessVerifier(
+ _errorReporter, _currentLibrary, workspacePackage),
_workspacePackage = workspacePackage {
_inDeprecatedMember = _currentLibrary.hasDeprecated;
@@ -524,6 +524,7 @@
if (importElement != null && importElement.isDeferred) {
_checkForLoadLibraryFunction(node, importElement);
}
+ _invalidAccessVerifier.verifyImport(node);
super.visitImportDirective(node);
}
@@ -674,6 +675,7 @@
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
_checkForDeprecatedMemberUse(node.staticElement, node);
+ _invalidAccessVerifier.verifySuperConstructorInvocation(node);
super.visitSuperConstructorInvocation(node);
}
@@ -1745,13 +1747,15 @@
final ErrorReporter _errorReporter;
final LibraryElement _library;
+ final WorkspacePackage _workspacePackage;
bool _inTemplateSource;
bool _inTestDirectory;
ClassElement _enclosingClass;
- _InvalidAccessVerifier(this._errorReporter, this._library) {
+ _InvalidAccessVerifier(
+ this._errorReporter, this._library, this._workspacePackage) {
var path = _library.source.fullName;
_inTemplateSource = path.contains(_templateExtension);
_inTestDirectory = path.contains(_testDir) ||
@@ -1759,20 +1763,19 @@
path.contains(_testingDir);
}
- /// Produces a hint if [identifier] is accessed from an invalid location. In
- /// particular:
+ /// Produces a hint if [identifier] is accessed from an invalid location.
///
- /// * if the given identifier is a protected closure, field or
- /// getter/setter, method closure or invocation accessed outside a subclass,
- /// or accessed outside the library wherein the identifier is declared, or
- /// * if the given identifier is a closure, field, getter, setter, method
- /// closure or invocation which is annotated with `visibleForTemplate`, and
- /// is accessed outside of the defining library, and the current library
- /// does not have the suffix '.template' in its source path, or
- /// * if the given identifier is a closure, field, getter, setter, method
- /// closure or invocation which is annotated with `visibleForTesting`, and
- /// is accessed outside of the defining library, and the current library
- /// does not have a directory named 'test' or 'testing' in its path.
+ /// In particular, a hint is produced in either of the two following cases:
+ ///
+ /// * The element associated with [identifier] is annotated with [internal],
+ /// and is accessed from outside the package in which the element is
+ /// declared.
+ /// * The element associated with [identifier] is annotated with [protected],
+ /// [visibleForTesting], and/or [visibleForTemplate], and is accessed from a
+ /// location which is invalid as per the rules of each such annotation.
+ /// Conversely, if the element is annotated with more than one of these
+ /// annotations, the access is valid (and no hint will be produced) if it
+ /// conforms to the rules of at least one of the annotations.
void verify(SimpleIdentifier identifier) {
if (identifier.inDeclarationContext() || _inCommentReference(identifier)) {
return;
@@ -1786,24 +1789,64 @@
}
AstNode grandparent = parent?.parent;
- Element element;
- String name;
- AstNode node;
-
- if (grandparent is ConstructorName) {
- element = grandparent.staticElement;
- name = grandparent.toSource();
- node = grandparent;
- } else {
- element = identifier.staticElement;
- name = identifier.name;
- node = identifier;
- }
+ var element = grandparent is ConstructorName
+ ? grandparent.staticElement
+ : identifier.staticElement;
if (element == null || _inCurrentLibrary(element)) {
return;
}
+ _checkForInvalidInternalAccess(identifier, element);
+ _checkForOtherInvalidAccess(identifier, element);
+ }
+
+ void verifyImport(ImportDirective node) {
+ var element = node.uriElement;
+ if (_hasInternal(element) &&
+ !_isLibraryInWorkspacePackage(element.library)) {
+ _errorReporter.reportErrorForNode(HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
+ node, [node.uri.stringValue]);
+ }
+ }
+
+ void verifySuperConstructorInvocation(SuperConstructorInvocation node) {
+ if (node.constructorName != null) {
+ // Named constructor calls are handled by [verify].
+ return;
+ }
+ var element = node.staticElement;
+ if (_hasInternal(element) &&
+ !_isLibraryInWorkspacePackage(element.library)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [element.name]);
+ }
+ }
+
+ void _checkForInvalidInternalAccess(
+ SimpleIdentifier identifier, Element element) {
+ if (_hasInternal(element) &&
+ !_isLibraryInWorkspacePackage(element.library)) {
+ String name;
+ AstNode node;
+
+ var grandparent = identifier.parent?.parent;
+
+ if (grandparent is ConstructorName) {
+ name = grandparent.toSource();
+ node = grandparent;
+ } else {
+ name = identifier.name;
+ node = identifier;
+ }
+
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [name]);
+ }
+ }
+
+ void _checkForOtherInvalidAccess(
+ SimpleIdentifier identifier, Element element) {
bool hasProtected = _hasProtected(element);
if (hasProtected) {
ClassElement definingClass = element.enclosingElement;
@@ -1827,8 +1870,22 @@
}
// At this point, [identifier] was not cleared as protected access, nor
- // cleared as access for templates or testing. Report the appropriate
- // violation(s).
+ // cleared as access for templates or testing. Report a violation for each
+ // annotation present.
+
+ String name;
+ AstNode node;
+
+ var grandparent = identifier.parent?.parent;
+
+ if (grandparent is ConstructorName) {
+ name = grandparent.toSource();
+ node = grandparent;
+ } else {
+ name = identifier.name;
+ node = identifier;
+ }
+
Element definingClass = element.enclosingElement;
if (hasProtected) {
_errorReporter.reportErrorForNode(
@@ -1851,6 +1908,19 @@
}
}
+ bool _hasInternal(Element element) {
+ if (element == null) {
+ return false;
+ }
+ if (element.hasInternal) {
+ return true;
+ }
+ if (element is PropertyAccessorElement && element.variable.hasInternal) {
+ return true;
+ }
+ return false;
+ }
+
bool _hasProtected(Element element) {
if (element is PropertyAccessorElement &&
element.enclosingElement is ClassElement &&
@@ -1912,6 +1982,15 @@
bool _inExportDirective(SimpleIdentifier identifier) =>
identifier.parent is Combinator &&
identifier.parent.parent is ExportDirective;
+
+ bool _isLibraryInWorkspacePackage(LibraryElement library) {
+ if (_workspacePackage == null || library == null) {
+ // Better to not make a big claim that they _are_ in the same package,
+ // if we were unable to determine what package [_currentLibrary] is in.
+ return false;
+ }
+ return _workspacePackage.contains(library.source);
+ }
}
/// A visitor that determines, upon visiting a function body and/or a
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index d80064f..20e0732 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -11,7 +11,6 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
-import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
import 'package:analyzer/src/error/codes.dart';
@@ -82,9 +81,6 @@
/// The element for the library containing the compilation unit being visited.
final LibraryElement _definingLibrary;
- /// The type representing the type 'dynamic'.
- DartType _dynamicType;
-
/// Whether constant evaluation errors should be reported during resolution.
@Deprecated('This field is no longer used')
final bool reportConstEvaluationErrors;
@@ -102,7 +98,6 @@
const MigratableAstInfoProvider()})
: _definingLibrary = _resolver.definingLibrary,
_typePropertyResolver = _resolver.typePropertyResolver {
- _dynamicType = _typeProvider.dynamicType;
_methodInvocationResolver = MethodInvocationResolver(
_resolver,
migratableAstInfoProvider,
@@ -375,34 +370,6 @@
}
@override
- void visitIndexExpression(IndexExpression node) {
- var hasRead = node.inGetterContext();
- var hasWrite = node.inSetterContext();
-
- var resolver = PropertyElementResolver(_resolver);
- var result = resolver.resolveIndexExpression(
- node: node,
- hasRead: hasRead,
- hasWrite: hasWrite,
- );
-
- if (hasRead && hasWrite) {
- node.staticElement = result.writeElement;
- node.auxiliaryElements = AuxiliaryElements(result.readElement);
- _resolver.setReadElement(node, result.readElement);
- _resolver.setWriteElement(node, result.writeElement);
- } else if (hasRead) {
- node.staticElement = result.readElement;
- _resolver.setReadElement(node, result.readElement);
- } else if (hasWrite) {
- node.staticElement = result.writeElement;
- _resolver.setWriteElement(node, result.writeElement);
- }
-
- InferenceContext.setType(node.index, result.indexContextType);
- }
-
- @override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
ConstructorElement invokedConstructor = node.constructorName.staticElement;
ArgumentList argumentList = node.argumentList;
@@ -439,160 +406,6 @@
}
@override
- void visitPrefixedIdentifier(PrefixedIdentifier node) {
- SimpleIdentifier prefix = node.prefix;
- SimpleIdentifier identifier = node.identifier;
- //
- // First, check the "lib.loadLibrary" case
- //
- if (identifier.name == FunctionElement.LOAD_LIBRARY_NAME &&
- _isDeferredPrefix(prefix)) {
- LibraryElement importedLibrary = _getImportedLibrary(prefix);
- var element = importedLibrary?.loadLibraryFunction;
- element = _resolver.toLegacyElement(element);
- identifier.staticElement = element;
- return;
- }
- //
- // Check to see whether the prefix is really a prefix.
- //
- Element prefixElement = prefix.staticElement;
- if (prefixElement is PrefixElement) {
- var lookupResult = prefixElement.scope.lookup2(identifier.name);
-
- if (identifier.inGetterContext()) {
- _resolver.setReadElement(
- node,
- _resolver.toLegacyElement(lookupResult.getter),
- );
- }
-
- if (identifier.inSetterContext()) {
- _resolver.setWriteElement(
- node,
- _resolver.toLegacyElement(lookupResult.setter),
- );
- }
-
- var element = lookupResult.getter;
- if (element == null && identifier.inSetterContext()) {
- element = lookupResult.setter;
- }
- element = _resolver.toLegacyElement(element);
- if (element == null && _resolver.nameScope.shouldIgnoreUndefined(node)) {
- return;
- }
- if (element == null) {
- AstNode parent = node.parent;
- if (parent is Annotation) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_ANNOTATION,
- parent,
- [identifier.name]);
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
- identifier,
- [identifier.name, prefixElement.name]);
- }
- return;
- }
- Element accessor = element;
- if (accessor is PropertyAccessorElement && identifier.inSetterContext()) {
- PropertyInducingElement variable = accessor.variable;
- if (variable != null) {
- PropertyAccessorElement setter = variable.setter;
- if (setter != null) {
- element = setter;
- }
- }
- }
- // TODO(brianwilkerson) The prefix needs to be resolved to the element for
- // the import that defines the prefix, not the prefix's element.
- identifier.staticElement = element;
- // Validate annotation element.
- AstNode parent = node.parent;
- if (parent is Annotation) {
- _resolveAnnotationElement(parent);
- }
- return;
- }
- // May be annotation, resolve invocation of "const" constructor.
- AstNode parent = node.parent;
- if (parent is Annotation) {
- _resolveAnnotationElement(parent);
- return;
- }
- //
- // Otherwise, the prefix is really an expression that happens to be a simple
- // identifier and this is really equivalent to a property access node.
- //
- {
- var hasRead = identifier.inGetterContext();
- var hasWrite = identifier.inSetterContext();
-
- var resolver = PropertyElementResolver(_resolver);
- var result = resolver.resolvePrefixedIdentifier(
- node: node,
- hasRead: hasRead,
- hasWrite: hasWrite,
- );
-
- if (hasRead) {
- _resolver.setReadElement(node, result.readElement);
- }
-
- if (hasWrite) {
- _resolver.setWriteElement(node, result.writeElement);
- }
-
- if (hasWrite) {
- identifier.staticElement = result.writeElement;
- if (hasRead) {
- identifier.auxiliaryElements = AuxiliaryElements(
- result.readElement,
- );
- }
- } else if (hasRead) {
- identifier.staticElement = result.readElement;
- }
- }
- }
-
- @override
- void visitPropertyAccess(PropertyAccess node) {
- var propertyName = node.propertyName;
- var hasRead = propertyName.inGetterContext();
- var hasWrite = propertyName.inSetterContext();
-
- var resolver = PropertyElementResolver(_resolver);
- var result = resolver.resolvePropertyAccess(
- node: node,
- hasRead: hasRead,
- hasWrite: hasWrite,
- );
-
- if (hasRead) {
- _resolver.setReadElement(node, result.readElement);
- }
-
- if (hasWrite) {
- _resolver.setWriteElement(node, result.writeElement);
- }
-
- if (hasWrite) {
- propertyName.staticElement = result.writeElement;
- if (hasRead) {
- propertyName.auxiliaryElements = AuxiliaryElements(
- result.readElement,
- );
- }
- } else if (hasRead) {
- propertyName.staticElement = result.readElement;
- }
- }
-
- @override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
ClassElement enclosingClass = _resolver.enclosingClass;
@@ -727,13 +540,6 @@
if (inGetterContext) {
_resolver.setReadElement(node, getter);
}
-
- //
- // Validate annotation element.
- //
- if (parent is Annotation) {
- _resolveAnnotationElement(parent);
- }
}
@override
@@ -799,7 +605,7 @@
@override
void visitSuperExpression(SuperExpression node) {
var context = SuperContext.of(node);
- if (context == SuperContext.static) {
+ if (context == SuperContext.annotation || context == SuperContext.static) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node);
} else if (context == SuperContext.extension) {
@@ -824,41 +630,6 @@
_resolveAnnotations(node.metadata);
}
- /// Assuming that the given [identifier] is a prefix for a deferred import,
- /// return the library that is being imported.
- LibraryElement _getImportedLibrary(SimpleIdentifier identifier) {
- PrefixElement prefixElement = identifier.staticElement as PrefixElement;
- List<ImportElement> imports =
- prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
- return imports[0].importedLibrary;
- }
-
- InterfaceType _instantiateAnnotationClass(ClassElement element) {
- return element.instantiate(
- typeArguments: List.filled(
- element.typeParameters.length,
- _dynamicType,
- ),
- nullabilitySuffix: _resolver.noneOrStarSuffix,
- );
- }
-
- /// Return `true` if the given [expression] is a prefix for a deferred import.
- bool _isDeferredPrefix(Expression expression) {
- if (expression is SimpleIdentifier) {
- Element element = expression.staticElement;
- if (element is PrefixElement) {
- List<ImportElement> imports =
- element.enclosingElement.getImportsWithPrefix(element);
- if (imports.length != 1) {
- return false;
- }
- return imports[0].isDeferred;
- }
- }
- return false;
- }
-
/// Return `true` if the given [node] can validly be resolved to a prefix:
/// * it is the prefix in an import directive, or
/// * it is the prefix in a prefixed identifier.
@@ -915,159 +686,6 @@
}
}
- void _resolveAnnotationConstructorInvocationArguments(
- Annotation annotation, ConstructorElement constructor) {
- ArgumentList argumentList = annotation.arguments;
- // error will be reported in ConstantVerifier
- if (argumentList == null) {
- return;
- }
- // resolve arguments to parameters
- List<ParameterElement> parameters =
- _resolveArgumentsToFunction(argumentList, constructor);
- if (parameters != null) {
- argumentList.correspondingStaticParameters = parameters;
- }
- }
-
- /// Continues resolution of the given [annotation].
- void _resolveAnnotationElement(Annotation annotation) {
- SimpleIdentifier nameNode1;
- SimpleIdentifier nameNode2;
- {
- Identifier annName = annotation.name;
- if (annName is PrefixedIdentifier) {
- nameNode1 = annName.prefix;
- nameNode2 = annName.identifier;
- } else {
- nameNode1 = annName as SimpleIdentifier;
- nameNode2 = null;
- }
- }
- SimpleIdentifier nameNode3 = annotation.constructorName;
- ConstructorElement constructor;
- bool undefined = false;
- //
- // CONST or Class(args)
- //
- if (nameNode1 != null && nameNode2 == null && nameNode3 == null) {
- Element element1 = nameNode1.staticElement;
- // CONST
- if (element1 is PropertyAccessorElement) {
- _resolveAnnotationElementGetter(annotation, element1);
- return;
- }
- // Class(args)
- if (element1 is ClassElement) {
- constructor = _instantiateAnnotationClass(element1)
- .lookUpConstructor(null, _definingLibrary);
- constructor = _resolver.toLegacyElement(constructor);
- } else if (element1 == null) {
- undefined = true;
- }
- }
- //
- // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args)
- //
- if (nameNode1 != null && nameNode2 != null && nameNode3 == null) {
- Element element1 = nameNode1.staticElement;
- Element element2 = nameNode2.staticElement;
- // Class.CONST - not resolved yet
- if (element1 is ClassElement) {
- element2 = element1.lookUpGetter(nameNode2.name, _definingLibrary);
- element2 = _resolver.toLegacyElement(element2);
- }
- // prefix.CONST or Class.CONST
- if (element2 is PropertyAccessorElement) {
- nameNode2.staticElement = element2;
- annotation.element = element2;
- _resolveAnnotationElementGetter(annotation, element2);
- return;
- }
- // prefix.Class()
- if (element2 is ClassElement) {
- constructor = element2.unnamedConstructor;
- constructor = _resolver.toLegacyElement(constructor);
- }
- // Class.constructor(args)
- if (element1 is ClassElement) {
- constructor = _instantiateAnnotationClass(element1)
- .lookUpConstructor(nameNode2.name, _definingLibrary);
- constructor = _resolver.toLegacyElement(constructor);
- nameNode2.staticElement = constructor;
- }
- if (element1 == null && element2 == null) {
- undefined = true;
- }
- }
- //
- // prefix.Class.CONST or prefix.Class.constructor(args)
- //
- if (nameNode1 != null && nameNode2 != null && nameNode3 != null) {
- Element element2 = nameNode2.staticElement;
- // element2 should be ClassElement
- if (element2 is ClassElement) {
- String name3 = nameNode3.name;
- // prefix.Class.CONST
- PropertyAccessorElement getter =
- element2.lookUpGetter(name3, _definingLibrary);
- if (getter != null) {
- getter = _resolver.toLegacyElement(getter);
- nameNode3.staticElement = getter;
- annotation.element = getter;
- _resolveAnnotationElementGetter(annotation, getter);
- return;
- }
- // prefix.Class.constructor(args)
- constructor = _instantiateAnnotationClass(element2)
- .lookUpConstructor(name3, _definingLibrary);
- constructor = _resolver.toLegacyElement(constructor);
- nameNode3.staticElement = constructor;
- } else if (element2 == null) {
- undefined = true;
- }
- }
- // we need constructor
- if (constructor == null) {
- if (!undefined) {
- // If the class was not found then we've already reported the error.
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
- }
- return;
- }
- // record element
- annotation.element = constructor;
- // resolve arguments
- _resolveAnnotationConstructorInvocationArguments(annotation, constructor);
- }
-
- void _resolveAnnotationElementGetter(
- Annotation annotation, PropertyAccessorElement accessorElement) {
- // accessor should be synthetic
- if (!accessorElement.isSynthetic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION_GETTER, annotation);
- return;
- }
- // variable should be constant
- VariableElement variableElement = accessorElement.variable;
- if (!variableElement.isConst) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
- return;
- }
- // no arguments
- if (annotation.arguments != null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ANNOTATION_WITH_NON_CLASS,
- annotation.name,
- [annotation.name]);
- }
- // OK
- return;
- }
-
/// Given an [argumentList] and the [executableElement] that will be invoked
/// using those argument, compute the list of parameters that correspond to
/// the list of arguments. An error will be reported if any of the arguments
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 208d851..89c2ca2 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -145,8 +145,7 @@
/// A flag indicating whether the analyzer [Parser] factory method
/// will return a fasta based parser or an analyzer based parser.
- static const bool useFasta =
- bool.fromEnvironment("useFastaParser", defaultValue: true);
+ static const bool useFasta = true;
/// The source being parsed.
final Source _source;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 07ea52c..3650e5b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -24,6 +24,7 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/dart/resolver/annotation_resolver.dart';
import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/binary_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
@@ -37,6 +38,8 @@
import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
import 'package:analyzer/src/dart/resolver/postfix_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/prefix_expression_resolver.dart';
+import 'package:analyzer/src/dart/resolver/prefixed_identifier_resolver.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
@@ -175,6 +178,7 @@
FunctionExpressionResolver _functionExpressionResolver;
ForResolver _forResolver;
PostfixExpressionResolver _postfixExpressionResolver;
+ PrefixedIdentifierResolver _prefixedIdentifierResolver;
PrefixExpressionResolver _prefixExpressionResolver;
VariableDeclarationResolver _variableDeclarationResolver;
YieldStatementResolver _yieldStatementResolver;
@@ -350,6 +354,7 @@
resolver: this,
flowAnalysis: _flowAnalysis,
);
+ _prefixedIdentifierResolver = PrefixedIdentifierResolver(this);
_prefixExpressionResolver = PrefixExpressionResolver(
resolver: this,
flowAnalysis: _flowAnalysis,
@@ -444,7 +449,10 @@
}
}
- void checkReadOfNotAssignedLocalVariable(SimpleIdentifier node) {
+ void checkReadOfNotAssignedLocalVariable(
+ SimpleIdentifier node,
+ Element element,
+ ) {
if (_flowAnalysis?.flow == null) {
return;
}
@@ -453,7 +461,6 @@
return;
}
- var element = node.staticElement;
if (element is VariableElement) {
var assigned = _flowAnalysis.isDefinitelyAssigned(node, element);
var unassigned = _flowAnalysis.isDefinitelyUnassigned(node, element);
@@ -580,6 +587,59 @@
_thisType = enclosingClass?.thisType;
}
+ /// Resolve LHS [node] of an assignment, an explicit [AssignmentExpression],
+ /// or implicit [PrefixExpression] or [PostfixExpression].
+ PropertyElementResolverResult resolveForWrite({
+ @required AstNode node,
+ @required bool hasRead,
+ }) {
+ if (node is IndexExpression) {
+ node.target?.accept(this);
+ startNullAwareIndexExpression(node);
+
+ var resolver = PropertyElementResolver(this);
+ var result = resolver.resolveIndexExpression(
+ node: node,
+ hasRead: hasRead,
+ hasWrite: true,
+ );
+
+ InferenceContext.setType(node.index, result.indexContextType);
+ node.index.accept(this);
+
+ return result;
+ } else if (node is PrefixedIdentifier) {
+ node.prefix?.accept(this);
+
+ var resolver = PropertyElementResolver(this);
+ return resolver.resolvePrefixedIdentifier(
+ node: node,
+ hasRead: hasRead,
+ hasWrite: true,
+ );
+ } else if (node is PropertyAccess) {
+ node.target?.accept(this);
+ startNullAwarePropertyAccess(node);
+
+ var resolver = PropertyElementResolver(this);
+ return resolver.resolvePropertyAccess(
+ node: node,
+ hasRead: hasRead,
+ hasWrite: true,
+ );
+ } else if (node is SimpleIdentifier) {
+ var resolver = PropertyElementResolver(this);
+ return resolver.resolveSimpleIdentifier(
+ node: node,
+ hasRead: hasRead,
+ hasWrite: true,
+ );
+ } else {
+ node.accept(this);
+ return PropertyElementResolverResult();
+ }
+ }
+
/// Visit the given [comment] if it is not `null`.
void safelyVisitComment(Comment comment) {
if (comment != null) {
@@ -587,6 +647,53 @@
}
}
+ /// TODO(scheglov) This is mostly necessary for backward compatibility.
+ /// Although we also use `staticElement` for `getType(left)` below.
+ void setAssignmentBackwardCompatibility({
+ @required CompoundAssignmentExpression assignment,
+ @required AstNode left,
+ @required bool hasRead,
+ }) {
+ if (left is IndexExpression) {
+ if (hasRead) {
+ left.staticElement = assignment.writeElement;
+ left.auxiliaryElements = AuxiliaryElements(assignment.readElement);
+ } else {
+ left.staticElement = assignment.writeElement;
+ }
+ inferenceHelper.recordStaticType(left, assignment.writeType);
+ return;
+ }
+
+ SimpleIdentifier leftIdentifier;
+ if (left is PrefixedIdentifier) {
+ leftIdentifier = left.identifier;
+ inferenceHelper.recordStaticType(left, assignment.writeType);
+ } else if (left is PropertyAccess) {
+ leftIdentifier = left.propertyName;
+ inferenceHelper.recordStaticType(left, assignment.writeType);
+ } else if (left is SimpleIdentifier) {
+ leftIdentifier = left;
+ } else {
+ return;
+ }
+
+ if (hasRead) {
+ var readElement = assignment.readElement;
+ if (readElement is PropertyAccessorElement) {
+ leftIdentifier.auxiliaryElements = AuxiliaryElements(readElement);
+ }
+ }
+
+ leftIdentifier.staticElement = assignment.writeElement;
+ if (assignment.readElement is VariableElement) {
+ var leftType = localVariableTypeProvider.getType(leftIdentifier);
+ inferenceHelper.recordStaticType(leftIdentifier, leftType);
+ } else {
+ inferenceHelper.recordStaticType(leftIdentifier, assignment.writeType);
+ }
+ }
+
void setReadElement(Expression node, Element element) {
DartType readType = DynamicTypeImpl.instance;
if (node is IndexExpression) {
@@ -711,22 +818,7 @@
identical(parent, _enclosingMixinDeclaration)) {
return;
}
- node.name?.accept(this);
- node.constructorName?.accept(this);
- Element element = node.element;
- if (element is ExecutableElement) {
- InferenceContext.setType(node.arguments, element.type);
- }
- node.arguments?.accept(this);
- node.accept(elementResolver);
- node.accept(typeAnalyzer);
- ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation;
- if (elementAnnotationImpl == null) {
- // Analyzer ignores annotations on "part of" directives.
- assert(parent is PartOfDirective);
- } else {
- elementAnnotationImpl.annotationAst = _createCloner().cloneNode(node);
- }
+ AnnotationResolver(this).resolve(node);
}
@override
@@ -1472,9 +1564,31 @@
void visitIndexExpression(IndexExpression node) {
node.target?.accept(this);
startNullAwareIndexExpression(node);
- node.accept(elementResolver);
+
+ var resolver = PropertyElementResolver(this);
+ var result = resolver.resolveIndexExpression(
+ node: node,
+ hasRead: true,
+ hasWrite: false,
+ );
+
+ var element = result.readElement;
+ node.staticElement = element;
+
+ InferenceContext.setType(node.index, result.indexContextType);
node.index?.accept(this);
- node.accept(typeAnalyzer);
+
+ DartType type;
+ if (identical(node.realTarget.staticType, NeverTypeImpl.instance)) {
+ type = NeverTypeImpl.instance;
+ } else if (element is MethodElement) {
+ type = element.returnType;
+ } else {
+ type = DynamicTypeImpl.instance;
+ }
+ inferenceHelper.recordStaticType(node, type);
+
+ nullShortingTermination(node);
}
@override
@@ -1632,13 +1746,7 @@
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
- //
- // We visit the prefix, but do not visit the identifier because it needs to
- // be visited in the context of the prefix.
- //
- node.prefix?.accept(this);
- node.accept(elementResolver);
- node.accept(typeAnalyzer);
+ _prefixedIdentifierResolver.resolve(node);
}
@override
@@ -1648,15 +1756,36 @@
@override
void visitPropertyAccess(PropertyAccess node) {
- //
- // We visit the target, but do not visit the property name because it needs
- // to be visited in the context of the property access node.
- //
- var target = node.target;
- target?.accept(this);
+ node.target?.accept(this);
startNullAwarePropertyAccess(node);
- node.accept(elementResolver);
- node.accept(typeAnalyzer);
+
+ var resolver = PropertyElementResolver(this);
+ var result = resolver.resolvePropertyAccess(
+ node: node,
+ hasRead: true,
+ hasWrite: false,
+ );
+
+ var element = result.readElement;
+
+ var propertyName = node.propertyName;
+ propertyName.staticElement = element;
+
+ DartType type;
+ if (element is MethodElement) {
+ type = element.type;
+ } else if (element is PropertyAccessorElement && element.isGetter) {
+ type = element.returnType;
+ } else {
+ type = DynamicTypeImpl.instance;
+ }
+
+ type = inferenceHelper.inferTearOff(node, propertyName, type);
+
+ inferenceHelper.recordStaticType(propertyName, type);
+ inferenceHelper.recordStaticType(node, type);
+
+ nullShortingTermination(node);
}
@override
@@ -1707,7 +1836,7 @@
return;
}
- checkReadOfNotAssignedLocalVariable(node);
+ checkReadOfNotAssignedLocalVariable(node, node.staticElement);
super.visitSimpleIdentifier(node);
}
@@ -1862,8 +1991,19 @@
void visitVariableDeclaration(VariableDeclaration node) {
_variableDeclarationResolver.resolve(node);
+ var declaredElement = node.declaredElement;
if (node.parent.parent is ForParts) {
- _define(node.declaredElement);
+ _define(declaredElement);
+ }
+
+ var initializer = node.initializer;
+ var parent = node.parent;
+ TypeAnnotation declaredType = (parent as VariableDeclarationList).type;
+ if (declaredType == null && initializer != null) {
+ var initializerStaticType = initializer.staticType;
+ if (initializerStaticType is TypeParameterType) {
+ _flowAnalysis?.flow?.promote(declaredElement, initializerStaticType);
+ }
}
}
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 3f662eb..610860c 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -15,6 +15,7 @@
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/migration.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -64,6 +65,8 @@
_localVariableTypeProvider = _resolver.localVariableTypeProvider;
}
+ InvocationInferenceHelper get _inferenceHelper => _resolver.inferenceHelper;
+
/// Is `true` if the library being analyzed is non-nullable by default.
bool get _isNonNullableByDefault =>
_featureSet.isEnabled(Feature.non_nullable);
@@ -215,32 +218,6 @@
@override
void visitFunctionExpression(FunctionExpression node) {}
- /// The Dart Language Specification, 12.29: <blockquote>An assignable expression of the form
- /// <i>e<sub>1</sub>[e<sub>2</sub>]</i> is evaluated as a method invocation of the operator method
- /// <i>[]</i> on <i>e<sub>1</sub></i> with argument <i>e<sub>2</sub></i>.</blockquote>
- @override
- void visitIndexExpression(IndexExpression node) {
- if (identical(node.realTarget.staticType, NeverTypeImpl.instance)) {
- recordStaticType(node, NeverTypeImpl.instance);
- } else {
- DartType type;
- if (node.inSetterContext()) {
- var parameters = node.staticElement?.parameters;
- if (parameters?.length == 2) {
- type = parameters[1].type;
- }
- } else {
- type = node.staticElement?.returnType;
- }
-
- type ??= _dynamicType;
-
- recordStaticType(node, type);
- }
-
- _resolver.nullShortingTermination(node);
- }
-
/// The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
/// either the form <i>new T.id(a<sub>1</sub>, …, a<sub>n</sub>)</i> or the form <i>new
/// T(a<sub>1</sub>, …, a<sub>n</sub>)</i> is <i>T</i>.</blockquote>
@@ -316,123 +293,6 @@
recordStaticType(node, _getStaticType(expression));
}
- /// See [visitSimpleIdentifier].
- @override
- void visitPrefixedIdentifier(PrefixedIdentifier node) {
- SimpleIdentifier prefixedIdentifier = node.identifier;
- Element staticElement = prefixedIdentifier.staticElement;
-
- if (staticElement is ExtensionElement) {
- _setExtensionIdentifierType(node);
- return;
- }
-
- if (identical(node.prefix.staticType, NeverTypeImpl.instance)) {
- recordStaticType(prefixedIdentifier, NeverTypeImpl.instance);
- recordStaticType(node, NeverTypeImpl.instance);
- return;
- }
-
- DartType staticType = _dynamicType;
- if (staticElement is ClassElement) {
- if (_isExpressionIdentifier(node)) {
- var type = _nonNullable(_typeProvider.typeType);
- node.staticType = type;
- node.identifier.staticType = type;
- }
- return;
- } else if (staticElement is DynamicElementImpl) {
- var type = _nonNullable(_typeProvider.typeType);
- node.staticType = type;
- node.identifier.staticType = type;
- return;
- } else if (staticElement is FunctionTypeAliasElement) {
- if (node.parent is TypeName) {
- // no type
- } else {
- var type = _nonNullable(_typeProvider.typeType);
- node.staticType = type;
- node.identifier.staticType = type;
- }
- return;
- } else if (staticElement is MethodElement) {
- staticType = staticElement.type;
- } else if (staticElement is PropertyAccessorElement) {
- staticType = _getTypeOfProperty(staticElement);
- } else if (staticElement is ExecutableElement) {
- staticType = staticElement.type;
- } else if (staticElement is VariableElement) {
- staticType = staticElement.type;
- }
-
- staticType = _inferTearOff(node, node.identifier, staticType);
- if (!_inferObjectAccess(node, staticType, prefixedIdentifier)) {
- recordStaticType(prefixedIdentifier, staticType);
- recordStaticType(node, staticType);
- }
- }
-
- /// The Dart Language Specification, 12.13: <blockquote> Property extraction allows for a member of
- /// an object to be concisely extracted from the object. If <i>o</i> is an object, and if <i>m</i>
- /// is the name of a method member of <i>o</i>, then
- /// * <i>o.m</i> is defined to be equivalent to: <i>(r<sub>1</sub>, …, r<sub>n</sub>,
- /// {p<sub>1</sub> : d<sub>1</sub>, …, p<sub>k</sub> : d<sub>k</sub>}){return
- /// o.m(r<sub>1</sub>, …, r<sub>n</sub>, p<sub>1</sub>: p<sub>1</sub>, …,
- /// p<sub>k</sub>: p<sub>k</sub>);}</i> if <i>m</i> has required parameters <i>r<sub>1</sub>,
- /// …, r<sub>n</sub></i>, and named parameters <i>p<sub>1</sub> … p<sub>k</sub></i>
- /// with defaults <i>d<sub>1</sub>, …, d<sub>k</sub></i>.
- /// * <i>(r<sub>1</sub>, …, r<sub>n</sub>, [p<sub>1</sub> = d<sub>1</sub>, …,
- /// p<sub>k</sub> = d<sub>k</sub>]){return o.m(r<sub>1</sub>, …, r<sub>n</sub>,
- /// p<sub>1</sub>, …, p<sub>k</sub>);}</i> if <i>m</i> has required parameters
- /// <i>r<sub>1</sub>, …, r<sub>n</sub></i>, and optional positional parameters
- /// <i>p<sub>1</sub> … p<sub>k</sub></i> with defaults <i>d<sub>1</sub>, …,
- /// d<sub>k</sub></i>.
- /// Otherwise, if <i>m</i> is the name of a getter member of <i>o</i> (declared implicitly or
- /// explicitly) then <i>o.m</i> evaluates to the result of invoking the getter. </blockquote>
- ///
- /// The Dart Language Specification, 12.17: <blockquote> ... a getter invocation <i>i</i> of the
- /// form <i>e.m</i> ...
- ///
- /// Let <i>T</i> be the static type of <i>e</i>. It is a static type warning if <i>T</i> does not
- /// have a getter named <i>m</i>.
- ///
- /// The static type of <i>i</i> is the declared return type of <i>T.m</i>, if <i>T.m</i> exists;
- /// otherwise the static type of <i>i</i> is dynamic.
- ///
- /// ... a getter invocation <i>i</i> of the form <i>C.m</i> ...
- ///
- /// It is a static warning if there is no class <i>C</i> in the enclosing lexical scope of
- /// <i>i</i>, or if <i>C</i> does not declare, implicitly or explicitly, a getter named <i>m</i>.
- ///
- /// The static type of <i>i</i> is the declared return type of <i>C.m</i> if it exists or dynamic
- /// otherwise.
- ///
- /// ... a top-level getter invocation <i>i</i> of the form <i>m</i>, where <i>m</i> is an
- /// identifier ...
- ///
- /// The static type of <i>i</i> is the declared return type of <i>m</i>.</blockquote>
- @override
- void visitPropertyAccess(PropertyAccess node) {
- SimpleIdentifier propertyName = node.propertyName;
- Element staticElement = propertyName.staticElement;
- DartType staticType = _dynamicType;
- if (staticElement is MethodElement) {
- staticType = staticElement.type;
- } else if (staticElement is PropertyAccessorElement) {
- staticType = _getTypeOfProperty(staticElement);
- } else {
- // TODO(brianwilkerson) Report this internal error.
- }
-
- staticType = _inferTearOff(node, node.propertyName, staticType);
-
- if (!_inferObjectAccess(node, staticType, propertyName)) {
- recordStaticType(propertyName, staticType);
- recordStaticType(node, staticType);
- _resolver.nullShortingTermination(node);
- }
- }
-
/// The Dart Language Specification, 12.9: <blockquote>The static type of a rethrow expression is
/// bottom.</blockquote>
@override
@@ -520,7 +380,7 @@
} else {
staticType = _dynamicType;
}
- staticType = _inferTearOff(node, node, staticType);
+ staticType = _inferenceHelper.inferTearOff(node, node, staticType);
recordStaticType(node, staticType);
}
@@ -738,63 +598,6 @@
}
}
- /// Given a property access [node] with static type [nodeType],
- /// and [id] is the property name being accessed, infer a type for the
- /// access itself and its constituent components if the access is to one of the
- /// methods or getters of the built in 'Object' type, and if the result type is
- /// a sealed type. Returns true if inference succeeded.
- bool _inferObjectAccess(
- Expression node, DartType nodeType, SimpleIdentifier id) {
- // If we have an access like `libraryPrefix.hashCode` don't infer it.
- if (node is PrefixedIdentifier &&
- node.prefix.staticElement is PrefixElement) {
- return false;
- }
- // Search for Object accesses.
- String name = id.name;
- PropertyAccessorElement inferredElement =
- _typeProvider.objectType.element.getGetter(name);
- if (inferredElement == null || inferredElement.isStatic) {
- return false;
- }
- inferredElement = _resolver.toLegacyElement(inferredElement);
- DartType inferredType = inferredElement.returnType;
- if (nodeType != null &&
- nodeType.isDynamic &&
- inferredType is InterfaceType &&
- _typeProvider.nonSubtypableClasses.contains(inferredType.element)) {
- recordStaticType(id, inferredType);
- recordStaticType(node, inferredType);
- return true;
- }
- return false;
- }
-
- /// Given an uninstantiated generic function type, referenced by the
- /// [identifier] in the tear-off [expression], try to infer the instantiated
- /// generic function type from the surrounding context.
- DartType _inferTearOff(
- Expression expression,
- SimpleIdentifier identifier,
- DartType tearOffType,
- ) {
- var context = InferenceContext.getContext(expression);
- if (context is FunctionType && tearOffType is FunctionType) {
- var typeArguments = _typeSystem.inferFunctionTypeInstantiation(
- context,
- tearOffType,
- errorReporter: _resolver.errorReporter,
- errorNode: expression,
- );
- (identifier as SimpleIdentifierImpl).tearOffTypeArgumentTypes =
- typeArguments;
- if (typeArguments.isNotEmpty) {
- return tearOffType.instantiate(typeArguments);
- }
- }
- return tearOffType;
- }
-
/// Return `true` if the given [node] is not a type literal.
bool _isExpressionIdentifier(Identifier node) {
var parent = node.parent;
diff --git a/pkg/analyzer/lib/src/test_utilities/platform.dart b/pkg/analyzer/lib/src/test_utilities/platform.dart
new file mode 100644
index 0000000..11507ee
--- /dev/null
+++ b/pkg/analyzer/lib/src/test_utilities/platform.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2020, 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 'dart:io';
+
+/// The EOL character to be used for source code in tests.
+final platformEol = Platform.isWindows ? '\r\n' : '\n';
+
+/// Normalizes content to use platform-specific newlines to ensure that
+/// when running on Windows \r\n is used even though source files are checked
+/// out using \n.
+String normalizeNewlinesForPlatform(String input) {
+ // Skip normalising for other platforms, as the gitattributes for the SDK
+ // will ensure all files are \n.
+ if (!Platform.isWindows) {
+ return input;
+ }
+
+ final newlinePattern = RegExp(r'\r?\n'); // either \r\n or \n
+ return input.replaceAll(newlinePattern, platformEol);
+}
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index f9ae380..35a067a 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -370,48 +370,6 @@
_createResolver();
}
- test_lookUpMethodInInterfaces() async {
- InterfaceType intType = _typeProvider.intType;
- //
- // abstract class A { int operator[](int index); }
- //
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- MethodElement operator =
- ElementFactory.methodElement("[]", intType, [intType]);
- classA.methods = <MethodElement>[operator];
- //
- // class B implements A {}
- //
- ClassElementImpl classB = ElementFactory.classElement2("B");
- _encloseElement(classB);
- classB.interfaces = <InterfaceType>[interfaceTypeStar(classA)];
- //
- // class C extends Object with B {}
- //
- ClassElementImpl classC = ElementFactory.classElement2("C");
- _encloseElement(classC);
- classC.mixins = <InterfaceType>[interfaceTypeStar(classB)];
- //
- // class D extends C {}
- //
- ClassElementImpl classD =
- ElementFactory.classElement("D", interfaceTypeStar(classC));
- _encloseElement(classD);
- //
- // D a;
- // a[i];
- //
- SimpleIdentifier array = AstTestFactory.identifier3("a");
- array.staticType = interfaceTypeStar(classD);
- IndexExpression expression = AstTestFactory.indexExpression(
- target: array,
- index: AstTestFactory.identifier3("i"),
- );
- expect(_resolveIndexExpression(expression), same(operator));
- _listener.assertNoErrors();
- }
-
test_visitBreakStatement_withLabel() async {
// loop: while (true) {
// break loop;
@@ -706,161 +664,6 @@
_listener.assertNoErrors();
}
- test_visitPrefixedIdentifier_nonDynamic() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- String getterName = "b";
- PropertyAccessorElement getter =
- ElementFactory.getterElement(getterName, false, _typeProvider.intType);
- classA.accessors = <PropertyAccessorElement>[getter];
- SimpleIdentifier target = AstTestFactory.identifier3("a");
- VariableElementImpl variable = ElementFactory.localVariableElement(target);
- variable.type = interfaceTypeStar(classA);
- target.staticElement = variable;
- target.staticType = interfaceTypeStar(classA);
- PrefixedIdentifier identifier = AstTestFactory.identifier(
- target, AstTestFactory.identifier3(getterName));
- _resolveNode(identifier);
- expect(identifier.staticElement, same(getter));
- expect(identifier.identifier.staticElement, same(getter));
- _listener.assertNoErrors();
- }
-
- test_visitPrefixedIdentifier_staticClassMember_getter() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- // set accessors
- String propName = "b";
- PropertyAccessorElement getter =
- ElementFactory.getterElement(propName, true, _typeProvider.intType);
- PropertyAccessorElement setter =
- ElementFactory.setterElement(propName, true, _typeProvider.intType);
- classA.accessors = <PropertyAccessorElement>[getter, setter];
- // prepare "A.b"
- SimpleIdentifier target = AstTestFactory.identifier3("A");
- target.staticElement = classA;
- target.staticType = interfaceTypeStar(classA);
- PrefixedIdentifier identifier =
- AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
- // resolve
- _resolveNode(identifier);
- expect(identifier.staticElement, same(getter));
- expect(identifier.identifier.staticElement, same(getter));
- _listener.assertNoErrors();
- }
-
- test_visitPrefixedIdentifier_staticClassMember_method() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- // set methods
- String propName = "m";
- var method = ElementFactory.methodElement("m", _typeProvider.intType);
- method.isStatic = true;
- classA.methods = <MethodElement>[method];
- // prepare "A.m"
- SimpleIdentifier target = AstTestFactory.identifier3("A");
- target.staticElement = classA;
- target.staticType = interfaceTypeStar(classA);
- PrefixedIdentifier identifier =
- AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
- AstTestFactory.expressionStatement(identifier);
- // resolve
- _resolveNode(identifier);
- expect(identifier.staticElement, same(method));
- expect(identifier.identifier.staticElement, same(method));
- _listener.assertNoErrors();
- }
-
- test_visitPrefixedIdentifier_staticClassMember_setter() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- // set accessors
- String propName = "b";
- PropertyAccessorElement getter =
- ElementFactory.getterElement(propName, true, _typeProvider.intType);
- PropertyAccessorElement setter =
- ElementFactory.setterElement(propName, true, _typeProvider.intType);
- classA.accessors = <PropertyAccessorElement>[getter, setter];
- // prepare "A.b = null"
- SimpleIdentifier target = AstTestFactory.identifier3("A");
- target.staticElement = classA;
- target.staticType = interfaceTypeStar(classA);
- PrefixedIdentifier identifier =
- AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
- AstTestFactory.assignmentExpression(
- identifier, TokenType.EQ, AstTestFactory.nullLiteral());
- // resolve
- _resolveNode(identifier);
- expect(identifier.staticElement, same(setter));
- expect(identifier.identifier.staticElement, same(setter));
- _listener.assertNoErrors();
- }
-
- test_visitPropertyAccess_getter_identifier() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- String getterName = "b";
- PropertyAccessorElement getter =
- ElementFactory.getterElement(getterName, false, _typeProvider.intType);
- classA.accessors = <PropertyAccessorElement>[getter];
- SimpleIdentifier target = AstTestFactory.identifier3("a");
- target.staticType = interfaceTypeStar(classA);
- PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName);
- _resolveNode(access);
- expect(access.propertyName.staticElement, same(getter));
- _listener.assertNoErrors();
- }
-
- test_visitPropertyAccess_getter_super() async {
- //
- // class A {
- // int get b;
- // }
- // class B {
- // ... super.m ...
- // }
- //
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- String getterName = "b";
- PropertyAccessorElement getter =
- ElementFactory.getterElement(getterName, false, _typeProvider.intType);
- classA.accessors = <PropertyAccessorElement>[getter];
- SuperExpression target = AstTestFactory.superExpression();
- var classB = ElementFactory.classElement("B", interfaceTypeStar(classA));
- _encloseElement(classB);
- target.staticType = interfaceTypeStar(classB);
- PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName);
- AstTestFactory.methodDeclaration2(
- null,
- null,
- null,
- null,
- AstTestFactory.identifier3("m"),
- AstTestFactory.formalParameterList(),
- AstTestFactory.expressionFunctionBody(access));
- _resolveNode(access);
- expect(access.propertyName.staticElement, same(getter));
- _listener.assertNoErrors();
- }
-
- test_visitPropertyAccess_setter_this() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- _encloseElement(classA);
- String setterName = "b";
- PropertyAccessorElement setter =
- ElementFactory.setterElement(setterName, false, _typeProvider.intType);
- classA.accessors = <PropertyAccessorElement>[setter];
- ThisExpression target = AstTestFactory.thisExpression();
- target.staticType = interfaceTypeStar(classA);
- PropertyAccess access = AstTestFactory.propertyAccess2(target, setterName);
- AstTestFactory.assignmentExpression(
- access, TokenType.EQ, AstTestFactory.integer(0));
- _resolveNode(access);
- expect(access.propertyName.staticElement, same(setter));
- _listener.assertNoErrors();
- }
-
test_visitSimpleIdentifier_classScope() async {
InterfaceType doubleType = _typeProvider.doubleType;
String fieldName = 'nan';
@@ -1039,19 +842,6 @@
}
}
- /// Return the element associated with the given expression after the resolver
- /// has resolved the expression.
- ///
- /// @param node the expression to be resolved
- /// @param definedElements the elements that are to be defined in the scope in
- /// which the element is being resolved
- /// @return the element to which the expression was resolved
- Element _resolveIndexExpression(IndexExpression node,
- [List<Element> definedElements]) {
- _resolveNode(node, definedElements);
- return node.staticElement;
- }
-
/// Return the element associated with the given identifier after the resolver
/// has resolved the identifier.
///
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 5d380c9..408930a 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -588,59 +588,6 @@
_listener.assertNoErrors();
}
- void test_visitPrefixedIdentifier_getter() {
- DartType boolType = _typeProvider.boolType;
- PropertyAccessorElementImpl getter =
- ElementFactory.getterElement("b", false, boolType);
- PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
- node.identifier.staticElement = getter;
- expect(_analyze(node), same(boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitPrefixedIdentifier_setter() {
- DartType boolType = _typeProvider.boolType;
- FieldElementImpl field =
- ElementFactory.fieldElement("b", false, false, false, boolType);
- PropertyAccessorElement setter = field.setter;
- PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
- node.identifier.staticElement = setter;
- expect(_analyze(node), same(boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitPrefixedIdentifier_variable() {
- VariableElementImpl variable = ElementFactory.localVariableElement2("b");
- variable.type = _typeProvider.boolType;
- PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
- node.identifier.staticElement = variable;
- expect(_analyze(node), same(_typeProvider.boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitPropertyAccess_static_getter() {
- DartType boolType = _typeProvider.boolType;
- PropertyAccessorElementImpl getter =
- ElementFactory.getterElement("b", false, boolType);
- PropertyAccess node =
- AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
- node.propertyName.staticElement = getter;
- expect(_analyze(node), same(boolType));
- _listener.assertNoErrors();
- }
-
- void test_visitPropertyAccess_static_setter() {
- DartType boolType = _typeProvider.boolType;
- FieldElementImpl field =
- ElementFactory.fieldElement("b", false, false, false, boolType);
- PropertyAccessorElement setter = field.setter;
- PropertyAccess node =
- AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
- node.propertyName.staticElement = setter;
- expect(_analyze(node), same(boolType));
- _listener.assertNoErrors();
- }
-
void test_visitSimpleStringLiteral() {
// "a"
Expression node = _resolvedString("a");
diff --git a/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart b/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
index 87109c8b..63715f5 100644
--- a/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
+++ b/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
@@ -841,6 +841,29 @@
_checkMatch([T], numStar, T_star, true, ['num <: T <: _']);
}
+ /// If `Q` is a legacy type `Q0*` then the match holds under constraint
+ /// set `C`:
+ /// If `P` is `dynamic` or `void` and `P` is a subtype match for `Q0`
+ /// under constraint set `C`.
+ test_left_top_right_legacy() {
+ var U = typeParameter('U', bound: objectNone);
+ var U_star = typeParameterTypeStar(U);
+
+ _checkMatch([U], dynamicNone, U_star, false, ['dynamic <: U <: _']);
+ _checkMatch([U], voidNone, U_star, false, ['void <: U <: _']);
+ }
+
+ /// If `Q` is `Q0?` the match holds under constraint set `C`:
+ /// Or if `P` is `dynamic` or `void` and `Object` is a subtype match
+ /// for `Q0` under constraint set `C`.
+ test_left_top_right_nullable() {
+ var U = typeParameter('U', bound: objectNone);
+ var U_question = typeParameterTypeQuestion(U);
+
+ _checkMatch([U], dynamicNone, U_question, false, ['Object <: U <: _']);
+ _checkMatch([U], voidNone, U_question, false, ['Object <: U <: _']);
+ }
+
/// If `P` is a type variable `X` in `L`, then the match holds:
/// Under constraint `_ <: X <: Q`.
test_left_typeParameter() {
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index f502c38..f096933 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:analyzer/src/dart/micro/libraries_log.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:matcher/matcher.dart';
@@ -24,6 +25,10 @@
String bPath;
String cPath;
+ String get _asyncLibraryPath => futureElement.library.source.fullName;
+
+ String get _coreLibraryPath => intElement.library.source.fullName;
+
@override
void setUp() {
super.setUp();
@@ -32,6 +37,57 @@
cPath = convertPath('/workspace/dart/test/lib/c.dart');
}
+ test_changeFile_log() async {
+ newFile(aPath, content: r'''
+class A {}
+''');
+
+ newFile(bPath, content: r'''
+import 'a.dart';
+A a;
+B b;
+''');
+
+ result = await resolveFile(bPath);
+ assertErrorsInResolvedUnit(result, [
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 22, 1),
+ ]);
+
+ newFile(aPath, content: r'''
+class A {}
+class B {}
+''');
+ fileResolver.changeFile(aPath);
+
+ result = await resolveFile(bPath);
+ assertErrorsInResolvedUnit(result, []);
+
+ // The failure of this check will be reported badly.
+ expect(fileResolver.librariesLogEntries, [
+ predicate((LoadLibrariesForTargetLogEntry entry) {
+ expect(entry.target.path, bPath);
+ var loadedPathSet = entry.loaded.map((f) => f.path).toSet();
+ expect(loadedPathSet, contains(aPath));
+ expect(loadedPathSet, contains(bPath));
+ expect(loadedPathSet, contains(_asyncLibraryPath));
+ expect(loadedPathSet, contains(_coreLibraryPath));
+ return true;
+ }),
+ predicate((ChangeFileLoadEntry entry) {
+ expect(entry.target, aPath);
+ var removedPathSet = entry.removed.map((f) => f.path).toSet();
+ expect(removedPathSet, {aPath, bPath});
+ return true;
+ }),
+ predicate((LoadLibrariesForTargetLogEntry entry) {
+ expect(entry.target.path, bPath);
+ var loadedPathSet = entry.loaded.map((f) => f.path).toSet();
+ expect(loadedPathSet, {aPath, bPath});
+ return true;
+ }),
+ ]);
+ }
+
test_changeFile_refreshedFiles() async {
newFile(aPath, content: r'''
class A {}
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 80975a0..0f36155 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -2600,4 +2600,34 @@
assertType(findNode.cascade('A()'), 'A');
}
+
+ test_typeArgumentTypes_generic_inferred_leftTop_dynamic() async {
+ await assertNoErrorsInCode('''
+void foo<T extends Object>(T? value) {}
+
+void f(dynamic o) {
+ foo(o);
+}
+''');
+
+ assertTypeArgumentTypes(
+ findNode.methodInvocation('foo(o)'),
+ ['Object'],
+ );
+ }
+
+ test_typeArgumentTypes_generic_inferred_leftTop_void() async {
+ await assertNoErrorsInCode('''
+void foo<T extends Object>(List<T?> value) {}
+
+void f(List<void> o) {
+ foo(o);
+}
+''');
+
+ assertTypeArgumentTypes(
+ findNode.methodInvocation('foo(o)'),
+ ['Object'],
+ );
+ }
}
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index 3cfa0ac..c4838ab 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -141,7 +141,27 @@
);
}
- test_inc_notLValue_typeLiteral_typeParameter() async {
+ test_inc_notLValue_simpleIdentifier_typeLiteral() async {
+ await assertErrorsInCode(r'''
+void f() {
+ int++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 13, 3),
+ ]);
+
+ assertPostfixExpression(
+ findNode.postfix('int++'),
+ readElement: intElement,
+ readType: 'dynamic',
+ writeElement: intElement,
+ writeType: 'dynamic',
+ element: null,
+ type: 'dynamic',
+ );
+ }
+
+ test_inc_notLValue_simpleIdentifier_typeLiteral_typeParameter() async {
await assertErrorsInCode(r'''
void f<T>() {
T++;
@@ -153,7 +173,7 @@
var postfix = findNode.postfix('T++');
assertPostfixExpression(
postfix,
- readElement: null,
+ readElement: findElement.typeParameter('T'),
readType: 'dynamic',
writeElement: findElement.typeParameter('T'),
writeType: 'dynamic',
@@ -165,7 +185,7 @@
postfix.operand,
readElement: findElement.typeParameter('T'),
writeElement: findElement.typeParameter('T'),
- type: 'Type',
+ type: 'dynamic',
);
}
@@ -474,26 +494,6 @@
type: 'num',
);
}
-
- test_inc_simpleIdentifier_typeLiteral() async {
- await assertErrorsInCode(r'''
-void f() {
- int++;
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 13, 3),
- ]);
-
- assertPostfixExpression(
- findNode.postfix('int++'),
- readElement: null,
- readType: 'dynamic',
- writeElement: intElement,
- writeType: 'dynamic',
- element: null,
- type: 'dynamic',
- );
- }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index 14ddc4ca..b6b4dec 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -215,6 +215,26 @@
);
}
+ test_plusPlus_notLValue_simpleIdentifier_typeLiteral() async {
+ await assertErrorsInCode(r'''
+void f() {
+ ++int;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 15, 3),
+ ]);
+
+ assertPrefixExpression(
+ findNode.prefix('++int'),
+ readElement: intElement,
+ readType: 'dynamic',
+ writeElement: intElement,
+ writeType: 'dynamic',
+ element: null,
+ type: 'dynamic',
+ );
+ }
+
test_plusPlus_prefixedIdentifier_instance() async {
await assertNoErrorsInCode(r'''
class A {
@@ -580,26 +600,6 @@
);
}
- test_plusPlus_simpleIdentifier_typeLiteral() async {
- await assertErrorsInCode(r'''
-void f() {
- ++int;
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 15, 3),
- ]);
-
- assertPrefixExpression(
- findNode.prefix('++int'),
- readElement: null,
- readType: 'dynamic',
- writeElement: intElement,
- writeType: 'dynamic',
- element: null,
- type: 'dynamic',
- );
- }
-
/// Verify that we get all necessary types when building the dependencies
/// graph during top-level inference.
test_plusPlus_topLevelInference() async {
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
index 40ce958..3ffe641 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
@@ -302,6 +302,7 @@
]);
}
+ @override
void test_internalIsLibSrc() async {
newFile(testPackageImplementationFilePath, content: r'''
import 'package:meta/meta.dart';
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_internal_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_internal_member_test.dart
new file mode 100644
index 0000000..c2757f1
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_internal_member_test.dart
@@ -0,0 +1,529 @@
+// Copyright (c) 2020, 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:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidUseOfInternalMemberTest);
+ });
+}
+
+@reflectiveTest
+class InvalidUseOfInternalMemberTest extends PubPackageResolutionTest {
+ String get fooPackageRootPath => '$workspaceRootPath/foo';
+
+ @override
+ String get testPackageRootPath => '/home/my';
+
+ @override
+ void setUp() {
+ super.setUp();
+ writeTestPackagePubspecYamlFile(PubspecYamlFileConfig());
+ writeTestPackageConfig(
+ PackageConfigFileBuilder()
+ ..add(name: 'foo', rootPath: fooPackageRootPath),
+ meta: true);
+ }
+
+ test_insidePackage() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+class A {}
+''');
+ newFile('$fooPackageRootPath/lib/a.dart', content: '''
+import 'src/a.dart';
+
+A a = A();
+''');
+ await resolveFile2('$fooPackageRootPath/lib/a.dart');
+
+ assertNoErrorsInResult();
+ }
+
+ test_outsidePackage_class() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+class A {}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+A a = A();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 34, 1),
+ ]);
+ }
+
+ test_outsidePackage_constructor_named() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal
+ C.named();
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+C a = C.named();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 40, 7),
+ ]);
+ }
+
+ test_outsidePackage_constructor_unnamed() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal
+ C();
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+C a = C();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 40, 1),
+ ]);
+ }
+
+ test_outsidePackage_enum() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+enum E {one}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+void f(E value) {}
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 41, 1),
+ ]);
+ }
+
+ test_outsidePackage_enumValue() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+enum E {@internal one}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+E f() => E.one;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 45, 3),
+ ]);
+ }
+
+ test_outsidePackage_extensionMethod() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+extension E on String {
+ @internal
+ int f() => 1;
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = 'hello'.f();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 50, 1),
+ ]);
+ }
+
+ test_outsidePackage_function() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a() => 1;
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a() + 1;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+ ]);
+ }
+
+ test_outsidePackage_function_generic() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a<T>() => 1;
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a<void>() + 1;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+ ]);
+ }
+
+ test_outsidePackage_function_generic_tearoff() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a<T>() => 1;
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int Function() b = a;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 53, 1),
+ ]);
+ }
+
+ test_outsidePackage_function_tearoff() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a() => 1;
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int Function() b = a;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 53, 1),
+ ]);
+ }
+
+ test_outsidePackage_inCommentReference() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int get a => 1;
+''');
+
+ await assertNoErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+/// This is quite similar to [a].
+int b = 1;
+''');
+ }
+
+ test_outsidePackage_library() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+@internal
+library a;
+import 'package:meta/meta.dart';
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 0, 32),
+ error(HintCode.UNUSED_IMPORT, 7, 24),
+ ]);
+ }
+
+ test_outsidePackage_method() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal
+ int m() => 1;
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 46, 1),
+ ]);
+ }
+
+ test_outsidePackage_method_generic() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal
+ int m<T>() => 1;
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m<void>();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 46, 1),
+ ]);
+ }
+
+ test_outsidePackage_method_subclassed() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal int f() => 1;
+}
+
+class D extends C {}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = D().f();
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 46, 1),
+ ]);
+ }
+
+ test_outsidePackage_method_subclassed_overridden() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal int f() => 1;
+}
+
+class D extends C {
+ int f() => 2;
+}
+''');
+
+ await assertNoErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = D().f();
+''');
+ }
+
+ test_outsidePackage_method_tearoff() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal
+ int m() => 1;
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int Function() a = C().m;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 57, 1),
+ ]);
+ }
+
+ test_outsidePackage_methodParameter_named() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ int m({@internal int a = 0}) => 1;
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m(a: 5);
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 48, 1),
+ ]);
+ }
+
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/28066')
+ test_outsidePackage_methodParameter_positional() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ int m([@internal int a = 0]) => 1;
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m(5);
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 48, 1),
+ ]);
+ }
+
+ test_outsidePackage_mixin() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+mixin A {}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class C with A {}
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 47, 1),
+ ]);
+ }
+
+ test_outsidePackage_pairedWithProtected() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal
+ @protected
+ void f() {}
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class D extends C {
+ void g() => f();
+}
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 68, 1),
+ ]);
+ }
+
+ test_outsidePackage_redirectingFactoryConstructor() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+import 'package:test/test.dart';
+class D implements C {
+ @internal D();
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class C {
+ factory C() = D;
+}
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 60, 1),
+ ]);
+ }
+
+ test_outsidePackage_superConstructor() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal C();
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class D extends C {
+ D() : super();
+}
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 62, 7),
+ ]);
+ }
+
+ test_outsidePackage_superConstructor_named() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+ @internal C.named();
+}
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class D extends C {
+ D() : super.named();
+}
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 68, 5),
+ ]);
+ }
+
+ test_outsidePackage_topLevelGetter() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int get a => 1;
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a + 1;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+ ]);
+ }
+
+ test_outsidePackage_typedef() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+typedef t = void Function();
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+t func = () {};
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 34, 1),
+ ]);
+ }
+
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/28066')
+ test_outsidePackage_typedefParameter() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+typedef T = void Function({@internal int a = 1});
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+void f(T t) => t(a: 5);
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+ ]);
+ }
+
+ test_outsidePackage_variable() async {
+ newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a = 1;
+''');
+
+ await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a + 1;
+''', [
+ error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 08a65a1..0711ccb 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -324,6 +324,8 @@
import 'invalid_uri_test.dart' as invalid_uri;
import 'invalid_use_of_covariant_in_extension_test.dart'
as invalid_use_of_covariant_in_extension;
+import 'invalid_use_of_internal_member_test.dart'
+ as invalid_use_of_internal_member;
import 'invalid_use_of_protected_member_test.dart'
as invalid_use_of_protected_member;
import 'invalid_use_of_visible_for_template_member_test.dart'
@@ -861,6 +863,7 @@
invalid_type_argument_in_const_set.main();
invalid_uri.main();
invalid_use_of_covariant_in_extension.main();
+ invalid_use_of_internal_member.main();
invalid_use_of_protected_member.main();
invalid_use_of_visible_for_template_member.main();
invalid_use_of_visible_for_testing_member.main();
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart
index 779d2d2..711ac51 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart
@@ -15,6 +15,16 @@
@reflectiveTest
class UndefinedAnnotationTest extends PubPackageResolutionTest {
+ test_identifier1_localVariable_const() async {
+ await assertNoErrorsInCode(r'''
+main() {
+ const a = 0;
+ g(@a x) {}
+ g(0);
+}
+''');
+ }
+
test_unresolved_identifier() async {
await assertErrorsInCode(r'''
@unresolved
diff --git a/pkg/analyzer_cli/lib/src/context_cache.dart b/pkg/analyzer_cli/lib/src/context_cache.dart
index bdbe19a..276ac43 100644
--- a/pkg/analyzer_cli/lib/src/context_cache.dart
+++ b/pkg/analyzer_cli/lib/src/context_cache.dart
@@ -111,7 +111,6 @@
_buildContextFeatureSet(contextOptions);
contextOptions.hint = !clOptions.disableHints;
- contextOptions.useFastaParser = clOptions.useFastaParser;
return contextOptions;
}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index e54f8ae..cff668d 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -104,9 +104,6 @@
/// (Or null if not enabled.)
final String perfReport;
- /// Whether to enable parsing via the Fasta parser.
- final bool useFastaParser;
-
/// Batch mode (for unit testing)
final bool batchMode;
@@ -177,7 +174,6 @@
log = cast(args['log']),
machineFormat = args['format'] == 'machine',
perfReport = cast(args['x-perf-report']),
- useFastaParser = cast(args['use-fasta-parser']),
batchMode = cast(args['batch']),
showPackageWarnings = cast(args['show-package-warnings']) ||
cast(args['package-warnings']) ||
@@ -443,14 +439,6 @@
defaultsTo: false,
negatable: false,
hide: true)
- // TODO(brianwilkerson) Remove the following option after we're sure that
- // it's no longer being used.
- ..addFlag('enable-assert-initializers',
- help:
- 'Enable parsing of asserts in constructor initializers (deprecated).',
- defaultsTo: null,
- negatable: false,
- hide: hide)
..addFlag('use-analysis-driver-memory-byte-store',
help: 'Use memory byte store, not the file system cache.',
defaultsTo: false,
@@ -477,15 +465,6 @@
'of "libraryUri".',
splitCommas: false,
hide: hide)
- ..addFlag('use-fasta-parser',
- help: 'Whether to enable parsing via the Fasta parser.',
- defaultsTo: true,
- hide: hide)
- ..addFlag('preview-dart-2',
- help: 'Enable the Dart 2.0 preview.',
- defaultsTo: true,
- hide: hide,
- negatable: true)
..addFlag('train-snapshot',
help: 'Analyze the given source for the purposes of training a '
'dartanalyzer snapshot.',
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 8d0c27a..126856d 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -27,12 +27,9 @@
defineReflectiveTests(BuildModeTest);
defineReflectiveTests(BuildModeSummaryDependenciesTest);
defineReflectiveTests(ExitCodesTest);
- defineReflectiveTests(ExitCodesTest_PreviewDart2);
defineReflectiveTests(LinterTest);
- defineReflectiveTests(LinterTest_PreviewDart2);
defineReflectiveTests(NonDartFilesTest);
defineReflectiveTests(OptionsTest);
- defineReflectiveTests(OptionsTest_PreviewDart2);
}, name: 'Driver');
}
@@ -93,8 +90,6 @@
AnalysisOptions get analysisOptions => driver.analysisDriver.analysisOptions;
- bool get usePreviewDart2 => false;
-
/// Normalize text with bullets.
String bulletToDash(StringSink item) => '$item'.replaceAll('•', '-');
@@ -127,9 +122,6 @@
];
}
cmd..addAll(sources.map(_adjustFileSpec))..addAll(args);
- if (usePreviewDart2) {
- cmd.insert(0, '--preview-dart-2');
- }
await driver.start(cmd);
}
@@ -772,12 +764,6 @@
});
}
- Future<void> test_enableAssertInitializer() async {
- await drive('data/file_with_assert_initializers.dart',
- args: ['--enable-assert-initializers']);
- expect(exitCode, 0);
- }
-
Future<void> test_fatalErrors() async {
await drive('data/file_with_error.dart');
expect(exitCode, 3);
@@ -836,12 +822,6 @@
}
@reflectiveTest
-class ExitCodesTest_PreviewDart2 extends ExitCodesTest {
- @override
- bool get usePreviewDart2 => true;
-}
-
-@reflectiveTest
class LinterTest extends BaseTest {
String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
@@ -938,12 +918,6 @@
}
@reflectiveTest
-class LinterTest_PreviewDart2 extends LinterTest {
- @override
- bool get usePreviewDart2 => true;
-}
-
-@reflectiveTest
class NonDartFilesTest extends BaseTest {
Future<void> test_analysisOptionsYaml() async {
await withTempDirAsync((tempDir) async {
@@ -1133,12 +1107,6 @@
}
}
-@reflectiveTest
-class OptionsTest_PreviewDart2 extends OptionsTest {
- @override
- bool get usePreviewDart2 => true;
-}
-
class TestSource implements Source {
TestSource();
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 188a92f..12ff74c 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -257,11 +257,6 @@
expect(failureMessage, equals('Invalid Dart SDK path: &&&&&'));
});
- test('--use-fasta-parser', () {
- var options = parse(['--use-fasta-parser', 'foo.dart']);
- expect(options.useFastaParser, isTrue);
- });
-
test('--train-snapshot', () {
var options = parse(['--train-snapshot', 'foo.dart']);
expect(options.trainSnapshot, isTrue);
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 3f3db93..61305c7 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -309,6 +309,29 @@
}
@override
+ void writeImportedName(List<Uri> uris, String name) {
+ assert(uris.isNotEmpty);
+ var imports = <ImportElement>[];
+ for (var uri in uris) {
+ imports.addAll(dartFileEditBuilder._getImportsForUri(uri));
+ }
+ var import = _getBestImportForName(imports, name);
+ if (import == null) {
+ var library = dartFileEditBuilder._importLibrary(uris[0]);
+ if (library.prefix != null) {
+ write(library.prefix);
+ write('.');
+ }
+ } else {
+ if (import.prefix != null) {
+ write(import.prefix.displayName);
+ write('.');
+ }
+ }
+ write(name);
+ }
+
+ @override
void writeLocalVariableDeclaration(String name,
{void Function() initializerWriter,
bool isConst = false,
@@ -940,6 +963,33 @@
return name;
}
+ /// Given a list of [imports] that do, or can, make the [name] visible in
+ /// scope, return the one that will lead to the cleanest code.
+ ImportElement _getBestImportForName(
+ List<ImportElement> imports, String name) {
+ if (imports.isEmpty) {
+ return null;
+ } else if (imports.length == 1) {
+ return imports[0];
+ }
+ imports.sort((first, second) {
+ // Prefer imports that make the name visible.
+ var firstDefinesName = first.namespace.definedNames.containsKey(name);
+ var secondDefinesName = second.namespace.definedNames.containsKey(name);
+ if (firstDefinesName != secondDefinesName) {
+ return firstDefinesName ? -1 : 1;
+ }
+ // Prefer imports without prefixes.
+ var firstHasPrefix = first.prefix != null;
+ var secondHasPrefix = second.prefix != null;
+ if (firstHasPrefix != secondHasPrefix) {
+ return firstHasPrefix ? 1 : -1;
+ }
+ return 0;
+ });
+ return imports[0];
+ }
+
/// Returns all variants of names by removing leading words one by one.
List<String> _getCamelWordCombinations(String name) {
var result = <String>[];
@@ -1100,24 +1150,41 @@
/// If a [methodBeingCopied] is provided, then the type parameters of that
/// method will be duplicated in the copy and will therefore be visible.
///
+ /// If [required] it `true`, then the type will be written even if it would
+ /// normally be omitted, such as with `dynamic`.
+ ///
/// Causes any libraries whose elements are used by the generated code, to be
/// imported.
- bool _writeType(DartType type, {ExecutableElement methodBeingCopied}) {
+ bool _writeType(DartType type,
+ {ExecutableElement methodBeingCopied, bool required = false}) {
type = _getVisibleType(type, methodBeingCopied: methodBeingCopied);
// If not a useful type, don't write it.
- if (type == null || type.isDynamic || type.isBottom) {
+ if (type == null) {
return false;
}
-
- var element = type.element;
-
+ if (type.isDynamic) {
+ if (required) {
+ write('dynamic');
+ return true;
+ }
+ return false;
+ }
+ if (type.isBottom) {
+ var library = dartFileEditBuilder.resolvedUnit.libraryElement;
+ if (library.isNonNullableByDefault) {
+ write('Never');
+ return true;
+ }
+ return false;
+ }
// The type `void` does not have an element.
if (type is VoidType) {
write('void');
return true;
}
+ var element = type.element;
// Typedef(s) are represented as GenericFunctionTypeElement(s).
if (element is GenericFunctionTypeElement &&
element.typeParameters.isEmpty &&
@@ -1143,9 +1210,6 @@
// Write the simple name.
var name = element.displayName;
write(name);
- if (type.nullabilitySuffix == NullabilitySuffix.question) {
- write('?');
- }
// Write type arguments.
if (type is ParameterizedType) {
@@ -1167,12 +1231,17 @@
if (i != 0) {
write(', ');
}
- _writeType(argument, methodBeingCopied: methodBeingCopied);
+ _writeType(argument,
+ required: true, methodBeingCopied: methodBeingCopied);
}
write('>');
}
}
+ if (type.nullabilitySuffix == NullabilitySuffix.question) {
+ write('?');
+ }
+
return true;
}
}
@@ -1535,6 +1604,15 @@
return null;
}
+ Iterable<ImportElement> _getImportsForUri(Uri uri) sync* {
+ for (var import in resolvedUnit.libraryElement.imports) {
+ var importUri = import.importedLibrary.source.uri;
+ if (importUri == uri) {
+ yield import;
+ }
+ }
+ }
+
/// Computes the best URI to import [uri] into the target library.
String _getLibraryUriText(Uri uri) {
if (uri.scheme == 'file') {
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
index fef21a1..1b513a2 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
@@ -148,6 +148,10 @@
DartType returnType,
String returnTypeGroupName});
+ /// Write the given [name], possibly with a prefix, assuming that the name can
+ /// be imported from any of the given [uris].
+ void writeImportedName(List<Uri> uris, String name);
+
/// Write the code for a declaration of a local variable with the given
/// [name]. If an [initializerWriter] is provided, it will be invoked to write
/// the content of the initializer. (The equal sign separating the variable
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 764a691..4a5ae22 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -538,6 +538,65 @@
expect(position.offset, equals(20));
}
+ Future<void> test_writeImportedName_hasImport_first() async {
+ // addSource(convertPath('/home/test/lib/foo.dart'), '');
+ var path = convertPath('/home/test/lib/test.dart');
+ addSource(path, '''
+import 'foo.dart';
+''');
+
+ var builder = newBuilder();
+ await builder.addDartFileEdit(path, (builder) {
+ builder.addInsertion(0, (builder) {
+ builder.writeImportedName([
+ Uri.parse('package:test/foo.dart'),
+ Uri.parse('package:test/bar.dart')
+ ], 'Foo');
+ });
+ });
+ var edit = getEdit(builder);
+ expect(edit.replacement, equalsIgnoringWhitespace('Foo'));
+ }
+
+ Future<void> test_writeImportedName_hasImport_second() async {
+ var path = convertPath('/home/test/lib/test.dart');
+ addSource(path, '''
+import 'bar.dart';
+''');
+
+ var builder = newBuilder();
+ await builder.addDartFileEdit(path, (builder) {
+ builder.addInsertion(0, (builder) {
+ builder.writeImportedName([
+ Uri.parse('package:test/foo.dart'),
+ Uri.parse('package:test/bar.dart')
+ ], 'Foo');
+ });
+ });
+ var edit = getEdit(builder);
+ expect(edit.replacement, equalsIgnoringWhitespace('Foo'));
+ }
+
+ Future<void> test_writeImportedName_needsImport() async {
+ var path = convertPath('/home/test/lib/test.dart');
+ addSource(path, '');
+
+ var builder = newBuilder();
+ await builder.addDartFileEdit(path, (builder) {
+ builder.addInsertion(0, (builder) {
+ builder.writeImportedName([
+ Uri.parse('package:test/foo.dart'),
+ Uri.parse('package:test/bar.dart')
+ ], 'Foo');
+ });
+ });
+ var edits = getEdits(builder);
+ expect(edits, hasLength(2));
+ expect(edits[0].replacement,
+ equalsIgnoringWhitespace("import 'package:test/foo.dart';\n"));
+ expect(edits[1].replacement, equalsIgnoringWhitespace('Foo'));
+ }
+
Future<void> test_writeLocalVariableDeclaration_noType_initializer() async {
var path = convertPath('/home/test/lib/test.dart');
var content = '''
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index c49dce7..0144da8 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -6,7 +6,7 @@
</head>
<body>
<h1>Common Types</h1>
-<version>1.2.0</version>
+<version>1.2.1</version>
<p>
This document contains a specification of the types that are common between
the analysis server wire protocol and the analysis server plugin wire
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index d76446b..ace1d4c 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -23,6 +23,7 @@
static const String enableCheckedMode = '--enable-checked-mode';
static const String enableAsserts = '--enable-asserts';
static const String enableNullAssertions = '--null-assertions';
+ static const String enableNativeNullAssertions = '--native-null-assertions';
static const String enableDiagnosticColors = '--enable-diagnostic-colors';
static const String experimentalTrackAllocations =
'--experimental-track-allocations';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 2922b61..5eeb420 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -444,6 +444,7 @@
(_) => setCheckedMode(Flags.enableCheckedMode)),
new OptionHandler(Flags.enableAsserts, passThrough),
new OptionHandler(Flags.enableNullAssertions, passThrough),
+ new OptionHandler(Flags.enableNativeNullAssertions, passThrough),
new OptionHandler(Flags.trustTypeAnnotations, setTrustTypeAnnotations),
new OptionHandler(Flags.trustPrimitives, passThrough),
new OptionHandler(Flags.trustJSInteropTypeAnnotations, passThrough),
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index f56563a..c93e774 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -69,6 +69,9 @@
bool get supportsLateFields => false;
@override
+ bool get supportsLateLoweringSentinel => false;
+
+ @override
bool get useStaticFieldLowering => false;
// TODO(johnniwinther,sigmund): Remove this when js-interop handles getter
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 110e36e..368ee30 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -253,8 +253,8 @@
bool enableNullAssertions = false;
/// Whether to generate code asserting that non-nullable return values of
- /// `@Native` methods are checked for being non-null.
- bool enableNativeReturnNullAssertions = false;
+ /// `@Native` methods or `JS()` invocations are checked for being non-null.
+ bool enableNativeNullAssertions = false;
/// Whether to generate a source-map file together with the output program.
bool generateSourceMap = true;
@@ -484,6 +484,8 @@
_hasOption(options, Flags.enableAsserts)
..enableNullAssertions = _hasOption(options, Flags.enableCheckedMode) ||
_hasOption(options, Flags.enableNullAssertions)
+ ..enableNativeNullAssertions =
+ _hasOption(options, Flags.enableNativeNullAssertions)
..experimentalTrackAllocations =
_hasOption(options, Flags.experimentalTrackAllocations)
..experimentalAllocationsPath = _extractStringOption(
@@ -634,11 +636,6 @@
if (_deferClassTypes) deferClassTypes = true;
if (_noDeferClassTypes) deferClassTypes = false;
- if (enableNullAssertions) {
- // TODO(sra): Add a command-line flag to control this independently.
- enableNativeReturnNullAssertions = true;
- }
-
if (_newDeferredSplit) newDeferredSplit = true;
if (_noNewDeferredSplit) newDeferredSplit = false;
}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index e2738fd..a43c369 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1547,7 +1547,7 @@
sourceInformation: null));
HInstruction value = pop();
// TODO(johnniwinther): Provide source information.
- if (options.enableNativeReturnNullAssertions) {
+ if (options.enableNativeNullAssertions) {
if (_isNonNullableByDefault(functionNode)) {
DartType type = _getDartTypeIfValid(functionNode.returnType);
if (dartTypes.isNonNullableIfSound(type)) {
@@ -4728,6 +4728,41 @@
// It is acceptable for the type parameter to be broader than the
// specified type.
}
+
+ _maybeAddNullCheckOnJS(invocation);
+ }
+
+ /// If [invocation] is a `JS()` invocation in a web library and the static
+ /// type is non-nullable, add a check to make sure it isn't null.
+ void _maybeAddNullCheckOnJS(ir.StaticInvocation invocation) {
+ if (options.enableNativeNullAssertions &&
+ _isInWebLibrary(invocation) &&
+ closedWorld.dartTypes
+ .isNonNullableIfSound(_getStaticType(invocation).type)) {
+ HInstruction code = pop();
+ push(new HNullCheck(
+ code, _abstractValueDomain.excludeNull(code.instructionType),
+ sticky: true));
+ }
+ }
+
+ /// Returns true if [node] belongs to dart:html and related libraries.
+ bool _isInWebLibrary(ir.TreeNode node) {
+ if (node == null) return false;
+ bool isWebLibrary(Uri importUri) =>
+ importUri.scheme == 'dart' &&
+ (importUri.path == 'html' ||
+ importUri.path == 'svg' ||
+ importUri.path == 'indexed_db' ||
+ importUri.path == 'web_audio' ||
+ importUri.path == 'web_gl' ||
+ importUri.path == 'web_sql' ||
+ importUri.path == 'html_common') ||
+ // Mock web library path for testing.
+ importUri.path
+ .contains('native_null_assertions/js_invocations_in_web_library');
+ if (node is ir.Library) return isWebLibrary(node.importUri);
+ return _isInWebLibrary(node.parent);
}
void _handleJsStringConcat(ir.StaticInvocation invocation) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index ced7369..3718f17d 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -925,7 +925,7 @@
HInstruction maybeAddNativeReturnNullCheck(
HInstruction node, HInstruction replacement, FunctionEntity method) {
- if (_options.enableNativeReturnNullAssertions) {
+ if (_options.enableNativeNullAssertions) {
if (method.library.isNonNullableByDefault) {
FunctionType type =
_closedWorld.elementEnvironment.getFunctionType(method);
diff --git a/pkg/dart_internal/pubspec.yaml b/pkg/dart_internal/pubspec.yaml
index 757bdf3..191de63 100644
--- a/pkg/dart_internal/pubspec.yaml
+++ b/pkg/dart_internal/pubspec.yaml
@@ -1,5 +1,5 @@
name: dart_internal
-version: 0.1.11-nullsafety
+version: 0.1.12-nullsafety
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
repository: https://github.com/dart-lang/sdk/tree/master/pkg/dart_internal
@@ -18,4 +18,4 @@
environment:
# Restrict the upper bound so that we can remove support for this in a later
# version of the SDK without it being a breaking change.
- sdk: ">=2.10.0-0.0 <2.10.0"
+ sdk: ">=2.10.0-0 <2.11.0"
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 47d0805..e57a2fb 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:io';
import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
show DiagnosticMessage, DiagnosticMessageHandler;
@@ -206,24 +205,29 @@
class ExpressionCompiler {
static final String debugProcedureName = '\$dartEval';
- final bool verbose;
+ final CompilerContext _context;
+ final CompilerOptions _options;
+ final List<String> errors;
final IncrementalCompiler _compiler;
final ProgramCompiler _kernel2jsCompiler;
final Component _component;
- final List<String> errors;
+
DiagnosticMessageHandler onDiagnostic;
void _log(String message) {
- if (verbose) {
- // writing to stdout breaks communication to
- // frontend server, which is done on stdin/stdout,
- // so we use stderr here instead
- stderr.writeln(message);
+ if (_options.verbose) {
+ _context.options.ticker.logMs(message);
}
}
- ExpressionCompiler(this._compiler, this._kernel2jsCompiler, this._component,
- {this.verbose, this.onDiagnostic, this.errors});
+ ExpressionCompiler(
+ this._options,
+ this.errors,
+ this._compiler,
+ this._kernel2jsCompiler,
+ this._component,
+ ) : onDiagnostic = _options.onDiagnostic,
+ _context = _compiler.context;
/// Compiles [expression] in [libraryUri] at [line]:[column] to JavaScript
/// in [moduleName].
@@ -256,11 +260,11 @@
String expression) async {
// 1. find dart scope where debugger is paused
- _log('ExpressionCompiler: compiling: $expression in $moduleName');
+ _log('Compiling expression in $moduleName:\n$expression');
var dartScope = await _findScopeAt(Uri.parse(libraryUri), line, column);
if (dartScope == null) {
- _log('ExpressionCompiler: scope not found at $libraryUri:$line:$column');
+ _log('Scope not found at $libraryUri:$line:$column');
return null;
}
@@ -280,8 +284,7 @@
var localJsScope =
dartScope.definitions.keys.map((variable) => jsScope[variable]);
- _log('ExpressionCompiler: dart scope: $dartScope');
- _log('ExpressionCompiler: substituted local JsScope: $localJsScope');
+ _log('Performed scope substitutions for expression');
// 3. compile dart expression to JS
@@ -289,7 +292,7 @@
await _compileExpression(dartScope, jsModules, moduleName, expression);
if (jsExpression == null) {
- _log('ExpressionCompiler: failed to compile $expression, $jsExpression');
+ _log('Failed to compile expression in $moduleName:\n$expression');
return null;
}
@@ -323,7 +326,8 @@
error.name + ": " + error.message;
}''';
- _log('ExpressionCompiler: compiled $expression to $callExpression');
+ _log(
+ 'Compiled expression in $moduleName:\n$expression to \n$callExpression');
return callExpression;
}
@@ -350,6 +354,7 @@
return null;
}
+ _log('Detected expression compilation scope');
return scope;
}
@@ -362,6 +367,8 @@
return library.library;
}
+
+ _log('Loaded library for expression');
return null;
});
}
@@ -415,8 +422,6 @@
Map<String, String> modules,
String currentModule,
String expression) async {
- // 1. Compile expression to kernel AST
-
var procedure = await _compiler.compileExpression(
expression,
scope.definitions,
@@ -426,6 +431,8 @@
scope.cls?.name,
scope.procedure.isStatic);
+ _log('Compiled expression to kernel');
+
// TODO: make this code clear and assumptions enforceable
// https://github.com/dart-lang/sdk/issues/43273
//
@@ -438,14 +445,12 @@
return null;
}
- _log('ExpressionCompiler: Kernel: ${procedure.leakingDebugToString()}');
-
- // 2. compile kernel AST to JS ast
-
var jsFun = _kernel2jsCompiler.emitFunctionIncremental(
scope.library, scope.cls, procedure.function, '$debugProcedureName');
- // 3. apply temporary workarounds for what ideally
+ _log('Generated JavaScript for expression');
+
+ // apply temporary workarounds for what ideally
// needs to be done in the compiler
// get private fields accessed by the evaluated expression
@@ -478,10 +483,6 @@
}
}
- _log('ExpressionCompiler: privateFields: $privateFields');
- _log('ExpressionCompiler: currentLibraries: $currentLibraries');
- _log('ExpressionCompiler: currentModules: $currentModules');
-
var body = js_ast.Block([
// require modules used in evaluated expression
...currentModules.keys.map((String variable) =>
@@ -495,15 +496,15 @@
]);
var jsFunModified = js_ast.Fun(jsFun.params, body);
- _log('ExpressionCompiler: JS AST: $jsFunModified');
- // 4. print JS ast to string for evaluation
+ // print JS ast to string for evaluation
var context = js_ast.SimpleJavaScriptPrintingContext();
var opts =
js_ast.JavaScriptPrintingOptions(allowKeywordsInProperties: true);
jsFunModified.accept(js_ast.Printer(opts, context));
+ _log('Performed JavaScript adjustments for expression');
return context.getText();
}
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 9cb61dc..85aa859 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -103,10 +103,11 @@
final _componentForModuleName = <String, Component>{};
final _componentModuleNames = <Component, String>{};
final ProcessedOptions _processedOptions;
+ final CompilerOptions _compilerOptions;
final Component _sdkComponent;
- ExpressionCompilerWorker._(this._processedOptions, this._sdkComponent,
- this.requestStream, this.sendResponse);
+ ExpressionCompilerWorker._(this._processedOptions, this._compilerOptions,
+ this._sdkComponent, this.requestStream, this.sendResponse);
static Future<ExpressionCompilerWorker> createFromArgs(
List<String> args, {
@@ -172,7 +173,7 @@
void Function(Map<String, dynamic>)
sendResponse, // Defaults to write to stdout
}) async {
- var options = CompilerOptions()
+ var compilerOptions = CompilerOptions()
..compileSdk = false
..sdkRoot = sdkRoot
..sdkSummary = sdkSummary
@@ -192,15 +193,15 @@
.cast<Map<String, dynamic>>();
sendResponse ??= (Map<String, dynamic> response) =>
stdout.writeln(json.encode(response));
- var processedOpts = ProcessedOptions(options: options);
+ var processedOptions = ProcessedOptions(options: compilerOptions);
- var sdkComponent = await CompilerContext(processedOpts)
+ var sdkComponent = await CompilerContext(processedOptions)
.runInContext<Component>((CompilerContext c) async {
- return processedOpts.loadSdkSummary(null);
+ return processedOptions.loadSdkSummary(null);
});
- return ExpressionCompilerWorker._(
- processedOpts, sdkComponent, requestStream, sendResponse)
+ return ExpressionCompilerWorker._(processedOptions, compilerOptions,
+ sdkComponent, requestStream, sendResponse)
.._update(sdkComponent, dartSdkModule);
}
@@ -238,6 +239,8 @@
/// Handles a `CompileExpression` request.
Future<Map<String, dynamic>> _compileExpression(
CompileExpressionRequest request) async {
+ _processedOptions.ticker.logMs('Compiling expression to JavaScript');
+
var libraryUri = Uri.parse(request.libraryUri);
if (libraryUri.scheme == 'dart') {
// compiling expressions inside the SDK currently fails because
@@ -264,16 +267,18 @@
uriToSource: originalComponent.uriToSource,
);
}
+ _processedOptions.ticker.logMs('Collected dependencies for expression');
errors.clear();
warnings.clear();
var incrementalCompiler = IncrementalCompiler.forExpressionCompilationOnly(
- CompilerContext(_processedOptions), component);
+ CompilerContext(_processedOptions), component, /*resetTicker*/ false);
var finalComponent =
await incrementalCompiler.computeDelta(entryPoints: [libraryUri]);
finalComponent.computeCanonicalNames();
+ _processedOptions.ticker.logMs('Computed delta for expression');
if (errors.isNotEmpty) {
return {
@@ -294,13 +299,15 @@
coreTypes: incrementalCompiler.getCoreTypes(),
);
+ compiler.emitModule(finalComponent);
+ _processedOptions.ticker.logMs('Emitted module for expression');
+
var expressionCompiler = ExpressionCompiler(
+ _compilerOptions,
+ errors,
incrementalCompiler,
compiler,
finalComponent,
- verbose: _processedOptions.verbose,
- onDiagnostic: _onDiagnosticHandler(errors, warnings),
- errors: errors,
);
var compiledProcedure = await expressionCompiler.compileExpressionToJs(
@@ -312,6 +319,8 @@
request.moduleName,
request.expression);
+ _processedOptions.ticker.logMs('Compiled expression to JavaScript');
+
return {
'errors': errors,
'warnings': warnings,
@@ -347,6 +356,9 @@
/// Loads in the specified dill files and invalidates any existing ones.
Future<Map<String, dynamic>> _updateDeps(UpdateDepsRequest request) async {
+ _processedOptions.ticker
+ .logMs('Updating dependencies for expression evaluation');
+
for (var input in request.inputs) {
var file =
_processedOptions.fileSystem.entityForUri(Uri.parse(input.path));
@@ -356,6 +368,9 @@
alwaysCreateNewNamedNodes: true);
_update(component, input.moduleName);
}
+
+ _processedOptions.ticker
+ .logMs('Updated dependencies for expression evaluation');
return {'succeeded': true};
}
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index d2fc5e5..a005aae 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -35,6 +35,9 @@
bool get supportsLateFields => false;
@override
+ bool get supportsLateLoweringSentinel => false;
+
+ @override
bool get useStaticFieldLowering => false;
// TODO(johnniwinther,sigmund): Remove this when js-interop handles getter
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 7374f49..4e4068e 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -140,10 +140,13 @@
kernel2jsCompiler.emitModule(component);
// create expression compiler
- var evaluator = ExpressionCompiler(compiler, kernel2jsCompiler, component,
- verbose: setup.options.verbose,
- onDiagnostic: setup.options.onDiagnostic,
- errors: setup.errors);
+ var evaluator = ExpressionCompiler(
+ setup.options,
+ setup.errors,
+ compiler,
+ kernel2jsCompiler,
+ component,
+ );
// collect all module names and paths
var moduleInfo = _collectModules(component);
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index 80a1d09..ba34ca2 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -24,17 +24,17 @@
}
const Version enableAlternativeInvalidationStrategyVersion =
- const Version(2, 10);
+ const Version(2, 11);
const Version enableConstantUpdate2018Version = const Version(2, 0);
const Version enableControlFlowCollectionsVersion = const Version(2, 0);
const Version enableExtensionMethodsVersion = const Version(2, 6);
-const Version enableNonNullableVersion = const Version(2, 10);
-const Version enableNonfunctionTypeAliasesVersion = const Version(2, 10);
+const Version enableNonNullableVersion = const Version(2, 11);
+const Version enableNonfunctionTypeAliasesVersion = const Version(2, 11);
const Version enableSetLiteralsVersion = const Version(2, 0);
const Version enableSpreadCollectionsVersion = const Version(2, 0);
-const Version enableTripleShiftVersion = const Version(2, 10);
-const Version enableValueClassVersion = const Version(2, 10);
-const Version enableVarianceVersion = const Version(2, 10);
+const Version enableTripleShiftVersion = const Version(2, 11);
+const Version enableValueClassVersion = const Version(2, 11);
+const Version enableVarianceVersion = const Version(2, 11);
ExperimentalFlag parseExperimentalFlag(String flag) {
switch (flag) {
@@ -93,31 +93,31 @@
};
const Map<ExperimentalFlag, Version> experimentEnabledVersion = {
- ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 10),
+ ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 11),
ExperimentalFlag.constantUpdate2018: const Version(2, 0),
ExperimentalFlag.controlFlowCollections: const Version(2, 0),
ExperimentalFlag.extensionMethods: const Version(2, 6),
- ExperimentalFlag.nonNullable: const Version(2, 10),
- ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 10),
+ ExperimentalFlag.nonNullable: const Version(2, 11),
+ ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 11),
ExperimentalFlag.setLiterals: const Version(2, 0),
ExperimentalFlag.spreadCollections: const Version(2, 0),
- ExperimentalFlag.tripleShift: const Version(2, 10),
- ExperimentalFlag.valueClass: const Version(2, 10),
- ExperimentalFlag.variance: const Version(2, 10),
+ ExperimentalFlag.tripleShift: const Version(2, 11),
+ ExperimentalFlag.valueClass: const Version(2, 11),
+ ExperimentalFlag.variance: const Version(2, 11),
};
const Map<ExperimentalFlag, Version> experimentReleasedVersion = {
- ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 10),
+ ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 11),
ExperimentalFlag.constantUpdate2018: const Version(2, 0),
ExperimentalFlag.controlFlowCollections: const Version(2, 0),
ExperimentalFlag.extensionMethods: const Version(2, 6),
ExperimentalFlag.nonNullable: const Version(2, 10),
- ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 10),
+ ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 11),
ExperimentalFlag.setLiterals: const Version(2, 0),
ExperimentalFlag.spreadCollections: const Version(2, 0),
- ExperimentalFlag.tripleShift: const Version(2, 10),
- ExperimentalFlag.valueClass: const Version(2, 10),
- ExperimentalFlag.variance: const Version(2, 10),
+ ExperimentalFlag.tripleShift: const Version(2, 11),
+ ExperimentalFlag.valueClass: const Version(2, 11),
+ ExperimentalFlag.variance: const Version(2, 11),
};
const AllowedExperimentalFlags defaultAllowedExperimentalFlags =
@@ -184,6 +184,9 @@
"meta": {
ExperimentalFlag.nonNullable,
},
+ "native_stack_traces": {
+ ExperimentalFlag.nonNullable,
+ },
"path": {
ExperimentalFlag.nonNullable,
},
diff --git a/pkg/front_end/lib/src/base/command_line_options.dart b/pkg/front_end/lib/src/base/command_line_options.dart
index f288ff5..776fc11 100644
--- a/pkg/front_end/lib/src/base/command_line_options.dart
+++ b/pkg/front_end/lib/src/base/command_line_options.dart
@@ -9,6 +9,8 @@
static const String nnbdWeakMode = "--nnbd-weak";
static const String forceLateLowering = "--force-late-lowering";
+ static const String forceLateLoweringSentinel =
+ "--force-late-lowering-sentinel";
static const String forceStaticFieldLowering =
"--force-static-field-lowering";
static const String forceNoExplicitGetterCalls =
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 928ef74..f3bf41e 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -10,8 +10,6 @@
import 'package:kernel/core_types.dart';
import 'package:kernel/src/legacy_erasure.dart';
-import '../../base/nnbd_mode.dart';
-
import '../constant_context.dart' show ConstantContext;
import '../fasta_codes.dart' show messageInternalProblemAlreadyInitialized;
@@ -126,7 +124,8 @@
Uri fileUri = libraryBuilder?.fileUri;
// If in mixed mode, late lowerings cannot use `null` as a sentinel on
// non-nullable fields since they can be assigned from legacy code.
- bool forceUseIsSetField = libraryBuilder.loader.nnbdMode != NnbdMode.Strong;
+ late_lowering.IsSetStrategy isSetStrategy =
+ late_lowering.computeIsSetStrategy(libraryBuilder);
if (isAbstract || isExternal) {
_fieldEncoding = new AbstractOrExternalFieldEncoding(fileUri, charOffset,
charEndOffset, getterReferenceFrom, setterReferenceFrom,
@@ -149,7 +148,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
} else {
_fieldEncoding = new LateFieldWithInitializerEncoding(
name,
@@ -161,7 +160,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
}
} else {
if (isFinal) {
@@ -175,7 +174,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
} else {
_fieldEncoding = new LateFieldWithoutInitializerEncoding(
name,
@@ -187,7 +186,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
}
}
} else if (libraryBuilder.isNonNullableByDefault &&
@@ -206,7 +205,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
} else {
_fieldEncoding = new LateFieldWithInitializerEncoding(
name,
@@ -218,7 +217,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
}
} else {
assert(lateIsSetReferenceFrom == null);
@@ -730,7 +729,8 @@
//
// This is used to force use isSet fields in mixed mode encoding since
// we cannot trust non-nullable fields to be initialized with non-null values.
- bool _forceUseIsSetField;
+ late_lowering.IsSetStrategy _isSetStrategy;
+ late_lowering.IsSetEncoding _isSetEncoding;
// If `true`, the is-set field was register before the type was known to be
// nullable or non-nullable. In this case we do not try to remove it from
@@ -751,22 +751,31 @@
Procedure getterReferenceFrom,
Procedure setterReferenceFrom,
bool isCovariant,
- bool forceUseIsSetField)
+ late_lowering.IsSetStrategy isSetStrategy)
: fileOffset = charOffset,
- _forceUseIsSetField = forceUseIsSetField,
- _forceIncludeIsSetField = forceUseIsSetField {
+ _isSetStrategy = isSetStrategy,
+ _forceIncludeIsSetField =
+ isSetStrategy == late_lowering.IsSetStrategy.forceUseIsSetField {
_field =
new Field(null, fileUri: fileUri, reference: referenceFrom?.reference)
..fileOffset = charOffset
..fileEndOffset = charEndOffset
..isNonNullableByDefault = true
..isInternalImplementation = true;
- _lateIsSetField = new Field(null,
- fileUri: fileUri, reference: lateIsSetReferenceFrom?.reference)
- ..fileOffset = charOffset
- ..fileEndOffset = charEndOffset
- ..isNonNullableByDefault = true
- ..isInternalImplementation = true;
+ switch (_isSetStrategy) {
+ case late_lowering.IsSetStrategy.useSentinelOrNull:
+ // [_lateIsSetField] is never needed.
+ break;
+ case late_lowering.IsSetStrategy.forceUseIsSetField:
+ case late_lowering.IsSetStrategy.useIsSetFieldOrNull:
+ _lateIsSetField = new Field(null,
+ fileUri: fileUri, reference: lateIsSetReferenceFrom?.reference)
+ ..fileOffset = charOffset
+ ..fileEndOffset = charEndOffset
+ ..isNonNullableByDefault = true
+ ..isInternalImplementation = true;
+ break;
+ }
_lateGetter = new Procedure(
null, ProcedureKind.Getter, new FunctionNode(null),
fileUri: fileUri, reference: getterReferenceFrom?.reference)
@@ -776,6 +785,12 @@
isCovariant: isCovariant);
}
+ late_lowering.IsSetEncoding get isSetEncoding {
+ assert(_type != null, "Type has not been computed for field $name.");
+ return _isSetEncoding ??=
+ late_lowering.computeIsSetEncoding(_type, _isSetStrategy);
+ }
+
@override
void completeSignature(CoreTypes coreTypes) {
if (_lateIsSetField != null) {
@@ -786,7 +801,15 @@
@override
void createBodies(CoreTypes coreTypes, Expression initializer) {
assert(_type != null, "Type has not been computed for field $name.");
- _field.initializer = new NullLiteral()..parent = _field;
+ if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
+ _field.initializer = new StaticInvocation(coreTypes.createSentinelMethod,
+ new Arguments([], types: [_type])..fileOffset = fileOffset)
+ ..parent = _field;
+ } else {
+ _field.initializer = new NullLiteral()
+ ..fileOffset = fileOffset
+ ..parent = _field;
+ }
if (_lateIsSetField != null) {
_lateIsSetField.initializer = new BoolLiteral(false)
..fileOffset = fileOffset
@@ -1073,7 +1096,7 @@
_createFieldSet(_field, value),
createIsSetWrite: (Expression value) =>
_createFieldSet(_lateIsSetField, value),
- useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+ isSetEncoding: isSetEncoding);
}
}
@@ -1086,7 +1109,7 @@
coreTypes, fileOffset, name, type, 'Field',
createVariableRead: _createFieldRead,
createIsSetRead: () => _createFieldGet(_lateIsSetField),
- useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+ isSetEncoding: isSetEncoding);
}
}
@@ -1102,7 +1125,7 @@
Procedure getterReferenceFrom,
Procedure setterReferenceFrom,
bool isCovariant,
- bool forceUseIsSetField)
+ late_lowering.IsSetStrategy isSetStrategy)
: super(
name,
fileUri,
@@ -1113,7 +1136,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
}
class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding
@@ -1128,7 +1151,7 @@
Procedure getterReferenceFrom,
Procedure setterReferenceFrom,
bool isCovariant,
- bool forceUseIsSetField)
+ late_lowering.IsSetStrategy isSetStrategy)
: super(
name,
fileUri,
@@ -1139,7 +1162,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
@override
Statement _createGetterBody(
@@ -1153,7 +1176,7 @@
createIsSetRead: () => _createFieldGet(_lateIsSetField),
createIsSetWrite: (Expression value) =>
_createFieldSet(_lateIsSetField, value),
- useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+ isSetEncoding: isSetEncoding);
}
}
@@ -1169,7 +1192,7 @@
Procedure getterReferenceFrom,
Procedure setterReferenceFrom,
bool isCovariant,
- bool forceUseIsSetField)
+ late_lowering.IsSetStrategy isSetStrategy)
: super(
name,
fileUri,
@@ -1180,7 +1203,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
@override
Statement _createSetterBody(
@@ -1195,7 +1218,7 @@
createIsSetRead: () => _createFieldGet(_lateIsSetField),
createIsSetWrite: (Expression value) =>
_createFieldSet(_lateIsSetField, value),
- useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+ isSetEncoding: isSetEncoding);
}
}
@@ -1210,7 +1233,7 @@
Procedure getterReferenceFrom,
Procedure setterReferenceFrom,
bool isCovariant,
- bool forceUseIsSetField)
+ late_lowering.IsSetStrategy isSetStrategy)
: super(
name,
fileUri,
@@ -1221,7 +1244,7 @@
getterReferenceFrom,
setterReferenceFrom,
isCovariant,
- forceUseIsSetField);
+ isSetStrategy);
@override
Statement _createGetterBody(
CoreTypes coreTypes, String name, Expression initializer) {
@@ -1233,7 +1256,8 @@
_createFieldSet(_field, value),
createIsSetRead: () => _createFieldGet(_lateIsSetField),
createIsSetWrite: (Expression value) =>
- _createFieldSet(_lateIsSetField, value));
+ _createFieldSet(_lateIsSetField, value),
+ isSetEncoding: isSetEncoding);
}
@override
@@ -1420,8 +1444,9 @@
..fileEndOffset = charEndOffset
..isNonNullableByDefault = isNonNullableByDefault;
if (!isFinal) {
- VariableDeclaration parameter = new VariableDeclaration(null)
- ..isCovariant = isCovariant;
+ VariableDeclaration parameter =
+ new VariableDeclaration("#externalFieldValue")
+ ..isCovariant = isCovariant;
_setter = new Procedure(
null,
ProcedureKind.Setter,
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 2c22a93..c1dd176 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -125,7 +125,7 @@
final CompilerContext context;
final Ticker ticker;
-
+ final bool resetTicker;
final bool outlineOnly;
bool trackNeededDillLibraries = false;
Set<Library> neededDillLibraries;
@@ -160,6 +160,7 @@
this.context, this.componentToInitializeFrom,
[bool outlineOnly, this.incrementalSerializer])
: ticker = context.options.ticker,
+ resetTicker = true,
initializeFromDillUri = null,
this.outlineOnly = outlineOnly ?? false,
this.initializedForExpressionCompilationOnly = false {
@@ -171,6 +172,7 @@
bool outlineOnly,
this.incrementalSerializer])
: ticker = context.options.ticker,
+ resetTicker = true,
componentToInitializeFrom = null,
this.outlineOnly = outlineOnly ?? false,
this.initializedForExpressionCompilationOnly = false {
@@ -178,8 +180,10 @@
}
IncrementalCompiler.forExpressionCompilationOnly(
- this.context, this.componentToInitializeFrom)
+ this.context, this.componentToInitializeFrom,
+ [bool resetTicker])
: ticker = context.options.ticker,
+ this.resetTicker = resetTicker ?? true,
initializeFromDillUri = null,
this.outlineOnly = false,
this.incrementalSerializer = null,
@@ -201,7 +205,9 @@
@override
Future<Component> computeDelta(
{List<Uri> entryPoints, bool fullComponent: false}) async {
- ticker.reset();
+ if (resetTicker) {
+ ticker.reset();
+ }
entryPoints ??= context.options.inputs;
return context.runInContext<Component>((CompilerContext c) async {
if (computeDeltaRunOnce && initializedForExpressionCompilationOnly) {
@@ -1570,6 +1576,7 @@
return await context.runInContext((_) async {
LibraryBuilder libraryBuilder =
userCode.loader.read(libraryUri, -1, accessor: userCode.loader.first);
+ ticker.logMs("Loaded library $libraryUri");
Class cls;
if (className != null) {
@@ -1597,6 +1604,7 @@
nameOrigin: libraryBuilder.library,
);
debugLibrary.setLanguageVersion(libraryBuilder.library.languageVersion);
+ ticker.logMs("Created debug library");
if (libraryBuilder is DillLibraryBuilder) {
for (LibraryDependency dependency
@@ -1629,6 +1637,7 @@
}
debugLibrary.addImportsToScope();
+ ticker.logMs("Added imports");
}
HybridFileSystem hfs = userCode.fileSystem;
@@ -1662,6 +1671,7 @@
// Make sure the library has a canonical name.
Component c = new Component(libraries: [debugLibrary.library]);
c.computeCanonicalNames();
+ ticker.logMs("Built debug library");
userCode.runProcedureTransformations(procedure);
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 713947d..7cc2d4d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2419,7 +2419,9 @@
.withArguments(token.lexeme),
token.charOffset,
token.length);
- } else if (isFinal && !isLate) {
+ } else if (!libraryBuilder.isNonNullableByDefault &&
+ isFinal &&
+ !isLate) {
initializer = buildProblem(
fasta.templateFinalFieldWithoutInitializer
.withArguments(token.lexeme),
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 31d4186..b053283 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -15,7 +15,6 @@
InstrumentationValueForMember,
InstrumentationValueForType,
InstrumentationValueForTypeArgs;
-import '../../base/nnbd_mode.dart';
import '../fasta_codes.dart';
import '../names.dart';
import '../problems.dart' show unhandled;
@@ -5629,6 +5628,7 @@
node.isImplicitlyTyped ? const UnknownType() : node.type;
DartType inferredType;
ExpressionInferenceResult initializerResult;
+ inferrer.flowAnalysis.declare(node, node.initializer != null);
if (node.initializer != null) {
initializerResult = inferrer.inferExpression(node.initializer,
declaredType, !inferrer.isTopLevel || node.isImplicitlyTyped,
@@ -5648,12 +5648,15 @@
node.type = inferredType;
}
if (initializerResult != null) {
+ DartType initializerType = initializerResult.inferredType;
+ if (node.isImplicitlyTyped && initializerType is TypeParameterType) {
+ inferrer.flowAnalysis.promote(node, initializerType);
+ }
Expression initializer = inferrer.ensureAssignableResult(
node.type, initializerResult,
fileOffset: node.fileOffset, isVoidAllowed: node.type is VoidType);
node.initializer = initializer..parent = node;
}
- inferrer.flowAnalysis.declare(node, node.initializer != null);
if (!inferrer.isTopLevel) {
SourceLibraryBuilder library = inferrer.library;
if (node.isImplicitlyTyped) {
@@ -5669,12 +5672,11 @@
List<Statement> result = <Statement>[];
result.add(node);
+ late_lowering.IsSetEncoding isSetEncoding =
+ late_lowering.computeIsSetEncoding(
+ node.type, late_lowering.computeIsSetStrategy(inferrer.library));
VariableDeclaration isSetVariable;
- if (node.type.isPotentiallyNullable ||
- // We cannot trust that non-nullable locals are not initialized to
- // `null` in mixed mode, so we use an `isSet` variable here.
- (inferrer.isNonNullableByDefault &&
- inferrer.nnbdMode != NnbdMode.Strong)) {
+ if (isSetEncoding == late_lowering.IsSetEncoding.useIsSetField) {
isSetVariable = new VariableDeclaration(
'${late_lowering.lateLocalPrefix}'
'${node.name}'
@@ -5717,7 +5719,7 @@
'Local',
createVariableRead: createVariableRead,
createIsSetRead: createIsSetRead,
- useIsSetField: isSetVariable != null)
+ isSetEncoding: isSetEncoding)
: late_lowering.createGetterWithInitializer(
inferrer.coreTypes,
fileOffset,
@@ -5728,7 +5730,7 @@
createVariableWrite: createVariableWrite,
createIsSetRead: createIsSetRead,
createIsSetWrite: createIsSetWrite,
- useIsSetField: isSetVariable != null),
+ isSetEncoding: isSetEncoding),
returnType: node.type))
..fileOffset = fileOffset;
getVariable.type =
@@ -5763,13 +5765,13 @@
createVariableWrite: createVariableWrite,
createIsSetRead: createIsSetRead,
createIsSetWrite: createIsSetWrite,
- useIsSetField: isSetVariable != null)
+ isSetEncoding: isSetEncoding)
: late_lowering.createSetterBody(inferrer.coreTypes,
fileOffset, node.name, setterParameter, node.type,
shouldReturnValue: true,
createVariableWrite: createVariableWrite,
createIsSetWrite: createIsSetWrite,
- useIsSetField: isSetVariable != null)
+ isSetEncoding: isSetEncoding)
..fileOffset = fileOffset,
positionalParameters: <VariableDeclaration>[
setterParameter
@@ -5784,8 +5786,15 @@
}
node.isLate = false;
node.lateType = node.type;
+ if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
+ node.initializer = new StaticInvocation(
+ inferrer.coreTypes.createSentinelMethod,
+ new Arguments([], types: [node.type])..fileOffset = fileOffset)
+ ..parent = node;
+ } else {
+ node.initializer = null;
+ }
node.type = inferrer.computeNullable(node.type);
- node.initializer = null;
return new StatementInferenceResult.multiple(node.fileOffset, result);
}
@@ -5865,16 +5874,26 @@
node.variable.name.length));
}
} else {
- if (isUnassigned &&
- declaredOrInferredType.isPotentiallyNonNullable) {
- return new ExpressionInferenceResult(
- resultType,
- inferrer.helper.wrapInProblem(
- resultExpression,
- templateNonNullableNotAssignedError
- .withArguments(node.variable.name),
- node.fileOffset,
- node.variable.name.length));
+ if (isUnassigned) {
+ if (variable.isFinal) {
+ return new ExpressionInferenceResult(
+ resultType,
+ inferrer.helper.wrapInProblem(
+ resultExpression,
+ templateFinalNotAssignedError
+ .withArguments(node.variable.name),
+ node.fileOffset,
+ node.variable.name.length));
+ } else if (declaredOrInferredType.isPotentiallyNonNullable) {
+ return new ExpressionInferenceResult(
+ resultType,
+ inferrer.helper.wrapInProblem(
+ resultExpression,
+ templateNonNullableNotAssignedError
+ .withArguments(node.variable.name),
+ node.fileOffset,
+ node.variable.name.length));
+ }
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index ab208ce..53d5493 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -963,9 +963,12 @@
for (FieldBuilder fieldBuilder in uninitializedFields) {
if (initializedFields == null ||
!initializedFields.contains(fieldBuilder)) {
+ bool uninitializedFinalOrNonNullableFieldIsError =
+ cls.enclosingLibrary.isNonNullableByDefault ||
+ (cls.constructors.isNotEmpty || cls.isMixinDeclaration);
if (!fieldBuilder.isLate) {
if (fieldBuilder.isFinal &&
- (cls.constructors.isNotEmpty || cls.isMixinDeclaration)) {
+ uninitializedFinalOrNonNullableFieldIsError) {
String uri = '${fieldBuilder.library.importUri}';
String file = fieldBuilder.fileUri.pathSegments.last;
if (uri == 'dart:html' ||
@@ -984,7 +987,7 @@
}
} else if (fieldBuilder.fieldType is! InvalidType &&
fieldBuilder.fieldType.isPotentiallyNonNullable &&
- (cls.constructors.isNotEmpty || cls.isMixinDeclaration)) {
+ uninitializedFinalOrNonNullableFieldIsError) {
SourceLibraryBuilder library = builder.library;
if (library.isNonNullableByDefault) {
library.addProblem(
@@ -1035,9 +1038,15 @@
templateFieldNonNullableNotInitializedByConstructorError
.withArguments(fieldBuilder.name, fieldBuilder.field.type,
library.isNonNullableByDefault),
- fieldBuilder.charOffset,
- fieldBuilder.name.length,
- fieldBuilder.fileUri);
+ constructorBuilder.charOffset,
+ noLength,
+ constructorBuilder.fileUri,
+ context: [
+ templateMissingImplementationCause
+ .withArguments(fieldBuilder.name)
+ .withLocation(fieldBuilder.fileUri,
+ fieldBuilder.charOffset, fieldBuilder.name.length)
+ ]);
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index 6fc6f43..3458ee9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -5,6 +5,8 @@
import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/core_types.dart';
+import '../../base/nnbd_mode.dart';
+import '../source/source_library_builder.dart';
import '../names.dart';
const String lateFieldPrefix = '_#';
@@ -27,66 +29,94 @@
Expression createVariableWrite(Expression value),
Expression createIsSetRead(),
Expression createIsSetWrite(Expression value),
- bool useIsSetField}) {
- assert(useIsSetField != null);
- if (useIsSetField) {
- // Generate:
- //
- // if (!_#isSet#field) {
- // _#field = <init>;
- // _#isSet#field = true
- // }
- // return _#field;
- return new Block(<Statement>[
- new IfStatement(
- new Not(createIsSetRead()..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- new Block(<Statement>[
- new ExpressionStatement(
- createVariableWrite(initializer)..fileOffset = fileOffset)
+ IsSetEncoding isSetEncoding}) {
+ assert(isSetEncoding != null);
+ switch (isSetEncoding) {
+ case IsSetEncoding.useIsSetField:
+ // Generate:
+ //
+ // if (!_#isSet#field) {
+ // _#field = <init>;
+ // _#isSet#field = true
+ // }
+ // return _#field;
+ return new Block(<Statement>[
+ new IfStatement(
+ new Not(createIsSetRead()..fileOffset = fileOffset)
..fileOffset = fileOffset,
- new ExpressionStatement(
- createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- ]),
- null)
- ..fileOffset = fileOffset,
- new ReturnStatement(
- // If [type] is a type variable with undetermined nullability we need
- // to create a read of the field that is promoted to the type variable
- // type.
- createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
- ..fileOffset = fileOffset
- ])
- ..fileOffset = fileOffset;
- } else {
- // Generate:
- //
- // return let # = _#field in # == null ? _#field = <init> : #;
- VariableDeclaration variable = new VariableDeclaration.forValue(
- createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
- type: type.withDeclaredNullability(Nullability.nullable))
- ..fileOffset = fileOffset;
- return new ReturnStatement(
- new Let(
- variable,
- new ConditionalExpression(
- new MethodInvocation(
- new VariableGet(variable)..fileOffset = fileOffset,
- equalsName,
- new Arguments(<Expression>[
- new NullLiteral()..fileOffset = fileOffset
- ])
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- createVariableWrite(initializer)..fileOffset = fileOffset,
- new VariableGet(variable, type)..fileOffset = fileOffset,
- type)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset;
+ new Block(<Statement>[
+ new ExpressionStatement(
+ createVariableWrite(initializer)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ new ExpressionStatement(
+ createIsSetWrite(
+ new BoolLiteral(true)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ ]),
+ null)
+ ..fileOffset = fileOffset,
+ new ReturnStatement(
+ // If [type] is a type variable with undetermined nullability we
+ // need to create a read of the field that is promoted to the type
+ // variable type.
+ createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+ ..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useSentinel:
+ // Generate:
+ //
+ // return let # = _#field in isSentinel(#) ? _#field = <init> : #;
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+ type: type.withDeclaredNullability(Nullability.nullable))
+ ..fileOffset = fileOffset;
+ return new ReturnStatement(
+ new Let(
+ variable,
+ new ConditionalExpression(
+ new StaticInvocation(
+ coreTypes.isSentinelMethod,
+ new Arguments(<Expression>[
+ new VariableGet(variable)..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createVariableWrite(initializer)..fileOffset = fileOffset,
+ new VariableGet(variable, type)..fileOffset = fileOffset,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useNull:
+ // Generate:
+ //
+ // return let # = _#field in # == null ? _#field = <init> : #;
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+ type: type.withDeclaredNullability(Nullability.nullable))
+ ..fileOffset = fileOffset;
+ return new ReturnStatement(
+ new Let(
+ variable,
+ new ConditionalExpression(
+ new MethodInvocation(
+ new VariableGet(variable)..fileOffset = fileOffset,
+ equalsName,
+ new Arguments(<Expression>[
+ new NullLiteral()..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createVariableWrite(initializer)..fileOffset = fileOffset,
+ new VariableGet(variable, type)..fileOffset = fileOffset,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
}
+ throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
}
/// Creates the body for the synthesized getter used to encode the lowering
@@ -106,7 +136,8 @@
{Expression createVariableRead({bool needsPromotion}),
Expression createVariableWrite(Expression value),
Expression createIsSetRead(),
- Expression createIsSetWrite(Expression value)}) {
+ Expression createIsSetWrite(Expression value),
+ IsSetEncoding isSetEncoding}) {
Expression exception = new Throw(new ConstructorInvocation(
coreTypes.lateInitializationErrorConstructor,
new Arguments(<Expression>[
@@ -121,93 +152,141 @@
VariableDeclaration temp =
new VariableDeclaration.forValue(initializer, type: type)
..fileOffset = fileOffset;
- if (type.isPotentiallyNullable) {
- // Generate:
- //
- // if (!_#isSet#field) {
- // var temp = <init>;
- // if (_#isSet#field) throw '...'
- // _#field = temp;
- // _#isSet#field = true
- // }
- // return _#field;
- return new Block(<Statement>[
- new IfStatement(
- new Not(createIsSetRead()..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- new Block(<Statement>[
- temp,
- new IfStatement(
- createIsSetRead()..fileOffset = fileOffset,
- new ExpressionStatement(exception)..fileOffset = fileOffset,
- null)
+ switch (isSetEncoding) {
+ case IsSetEncoding.useIsSetField:
+ // Generate:
+ //
+ // if (!_#isSet#field) {
+ // var temp = <init>;
+ // if (_#isSet#field) throw '...'
+ // _#field = temp;
+ // _#isSet#field = true
+ // }
+ // return _#field;
+ return new Block(<Statement>[
+ new IfStatement(
+ new Not(createIsSetRead()..fileOffset = fileOffset)
..fileOffset = fileOffset,
- new ExpressionStatement(
- createVariableWrite(
- new VariableGet(temp)..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- new ExpressionStatement(
- createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- ]),
- null)
- ..fileOffset = fileOffset,
- new ReturnStatement(
- // If [type] is a type variable with undetermined nullability we need
- // to create a read of the field that is promoted to the type variable
- // type.
- createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
- ..fileOffset = fileOffset
- ])
- ..fileOffset = fileOffset;
- } else {
- // Generate:
- //
- // return let #1 = _#field in #1 == null
- // ? let #2 = <init> in _#field == null ? _#field = #2 : throw '...'
- // : #1;
- VariableDeclaration variable = new VariableDeclaration.forValue(
- createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
- type: type.withDeclaredNullability(Nullability.nullable))
- ..fileOffset = fileOffset;
- return new ReturnStatement(
- new Let(
- variable,
- new ConditionalExpression(
- new MethodInvocation(
- new VariableGet(variable)..fileOffset = fileOffset,
- equalsName,
- new Arguments(<Expression>[
- new NullLiteral()..fileOffset = fileOffset
- ])
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- new Let(
- temp,
- new ConditionalExpression(
- new MethodInvocation(
- createVariableRead(needsPromotion: false)
- ..fileOffset = fileOffset,
- equalsName,
- new Arguments(<Expression>[
- new NullLiteral()..fileOffset = fileOffset
- ])
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- createVariableWrite(
- new VariableGet(temp)..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- exception,
- type)
- ..fileOffset = fileOffset),
- new VariableGet(variable, type)..fileOffset = fileOffset,
- type)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset;
+ new Block(<Statement>[
+ temp,
+ new IfStatement(
+ createIsSetRead()..fileOffset = fileOffset,
+ new ExpressionStatement(exception)..fileOffset = fileOffset,
+ null)
+ ..fileOffset = fileOffset,
+ new ExpressionStatement(
+ createVariableWrite(
+ new VariableGet(temp)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ new ExpressionStatement(
+ createIsSetWrite(
+ new BoolLiteral(true)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ ]),
+ null)
+ ..fileOffset = fileOffset,
+ new ReturnStatement(
+ // If [type] is a type variable with undetermined nullability we
+ // need to create a read of the field that is promoted to the type
+ // variable type.
+ createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+ ..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useSentinel:
+ // Generate:
+ //
+ // return let #1 = _#field in isSentinel(#1)
+ // ? let #2 = <init> in isSentinel(_#field)
+ // ? _#field = #2 : throw '...'
+ // : #1;
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+ type: type)
+ ..fileOffset = fileOffset;
+ return new ReturnStatement(
+ new Let(
+ variable,
+ new ConditionalExpression(
+ new StaticInvocation(
+ coreTypes.isSentinelMethod,
+ new Arguments(<Expression>[
+ new VariableGet(variable)..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ new Let(
+ temp,
+ new ConditionalExpression(
+ new StaticInvocation(
+ coreTypes.isSentinelMethod,
+ new Arguments(<Expression>[
+ createVariableRead(needsPromotion: false)
+ ..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createVariableWrite(
+ new VariableGet(temp)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ exception,
+ type)
+ ..fileOffset = fileOffset),
+ new VariableGet(variable)..fileOffset = fileOffset,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useNull:
+ // Generate:
+ //
+ // return let #1 = _#field in #1 == null
+ // ? let #2 = <init> in _#field == null
+ // ? _#field = #2 : throw '...'
+ // : #1;
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+ type: type.withDeclaredNullability(Nullability.nullable))
+ ..fileOffset = fileOffset;
+ return new ReturnStatement(
+ new Let(
+ variable,
+ new ConditionalExpression(
+ new MethodInvocation(
+ new VariableGet(variable)..fileOffset = fileOffset,
+ equalsName,
+ new Arguments(<Expression>[
+ new NullLiteral()..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ new Let(
+ temp,
+ new ConditionalExpression(
+ new MethodInvocation(
+ createVariableRead(needsPromotion: false)
+ ..fileOffset = fileOffset,
+ equalsName,
+ new Arguments(<Expression>[
+ new NullLiteral()..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createVariableWrite(
+ new VariableGet(temp)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ exception,
+ type)
+ ..fileOffset = fileOffset),
+ new VariableGet(variable, type)..fileOffset = fileOffset,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
}
+ throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
}
/// Creates the body for the synthesized getter used to encode the lowering
@@ -216,8 +295,8 @@
int fileOffset, String name, DartType type, String variableKindName,
{Expression createVariableRead({bool needsPromotion}),
Expression createIsSetRead(),
- bool useIsSetField}) {
- assert(useIsSetField != null);
+ IsSetEncoding isSetEncoding}) {
+ assert(isSetEncoding != null);
Expression exception = new Throw(new ConstructorInvocation(
coreTypes.lateInitializationErrorConstructor,
new Arguments(<Expression>[
@@ -228,46 +307,73 @@
..fileOffset = fileOffset)
..fileOffset = fileOffset)
..fileOffset = fileOffset;
- if (useIsSetField) {
- // Generate:
- //
- // return _#isSet#field ? _#field : throw '...';
- return new ReturnStatement(
- new ConditionalExpression(
- createIsSetRead()..fileOffset = fileOffset,
- createVariableRead(needsPromotion: type.isPotentiallyNonNullable)
- ..fileOffset = fileOffset,
- exception,
- type)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset;
- } else {
- // Generate:
- //
- // return let # = _#field in # == null ? throw '...' : #;
- VariableDeclaration variable = new VariableDeclaration.forValue(
- createVariableRead()..fileOffset = fileOffset,
- type: type.withDeclaredNullability(Nullability.nullable))
- ..fileOffset = fileOffset;
- return new ReturnStatement(
- new Let(
- variable,
- new ConditionalExpression(
- new MethodInvocation(
- new VariableGet(variable)..fileOffset = fileOffset,
- equalsName,
- new Arguments(<Expression>[
- new NullLiteral()..fileOffset = fileOffset
- ])
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- exception,
- new VariableGet(variable, type)..fileOffset = fileOffset,
- type)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset;
+ switch (isSetEncoding) {
+ case IsSetEncoding.useIsSetField:
+ // Generate:
+ //
+ // return _#isSet#field ? _#field : throw '...';
+ return new ReturnStatement(
+ new ConditionalExpression(
+ createIsSetRead()..fileOffset = fileOffset,
+ createVariableRead(needsPromotion: type.isPotentiallyNonNullable)
+ ..fileOffset = fileOffset,
+ exception,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useSentinel:
+ // Generate:
+ //
+ // return let # = _#field in isSentinel(#) ? throw '...' : #;
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ createVariableRead()..fileOffset = fileOffset,
+ type: type.withDeclaredNullability(Nullability.nullable))
+ ..fileOffset = fileOffset;
+ return new ReturnStatement(
+ new Let(
+ variable,
+ new ConditionalExpression(
+ new StaticInvocation(
+ coreTypes.isSentinelMethod,
+ new Arguments(<Expression>[
+ new VariableGet(variable)..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ exception,
+ new VariableGet(variable, type)..fileOffset = fileOffset,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useNull:
+ // Generate:
+ //
+ // return let # = _#field in # == null ? throw '...' : #;
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ createVariableRead()..fileOffset = fileOffset,
+ type: type.withDeclaredNullability(Nullability.nullable))
+ ..fileOffset = fileOffset;
+ return new ReturnStatement(
+ new Let(
+ variable,
+ new ConditionalExpression(
+ new MethodInvocation(
+ new VariableGet(variable)..fileOffset = fileOffset,
+ equalsName,
+ new Arguments(<Expression>[
+ new NullLiteral()..fileOffset = fileOffset
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ exception,
+ new VariableGet(variable, type)..fileOffset = fileOffset,
+ type)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
}
+ throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
}
/// Creates the body for the synthesized setter used to encode the lowering
@@ -277,8 +383,8 @@
{bool shouldReturnValue,
Expression createVariableWrite(Expression value),
Expression createIsSetWrite(Expression value),
- bool useIsSetField}) {
- assert(useIsSetField != null);
+ IsSetEncoding isSetEncoding}) {
+ assert(isSetEncoding != null);
Statement createReturn(Expression value) {
if (shouldReturnValue) {
return new ReturnStatement(value)..fileOffset = fileOffset;
@@ -291,27 +397,30 @@
createVariableWrite(new VariableGet(parameter)..fileOffset = fileOffset)
..fileOffset = fileOffset);
- if (useIsSetField) {
- // Generate:
- //
- // _#isSet#field = true;
- // return _#field = parameter
- //
- return new Block([
- new ExpressionStatement(
- createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- assignment
- ])
- ..fileOffset = fileOffset;
- } else {
- // Generate:
- //
- // return _#field = parameter
- //
- return assignment;
+ switch (isSetEncoding) {
+ case IsSetEncoding.useIsSetField:
+ // Generate:
+ //
+ // _#isSet#field = true;
+ // return _#field = parameter
+ //
+ return new Block([
+ new ExpressionStatement(
+ createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ assignment
+ ])
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useSentinel:
+ case IsSetEncoding.useNull:
+ // Generate:
+ //
+ // return _#field = parameter
+ //
+ return assignment;
}
+ throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
}
/// Creates the body for the synthesized setter used to encode the lowering
@@ -328,8 +437,8 @@
Expression createVariableWrite(Expression value),
Expression createIsSetRead(),
Expression createIsSetWrite(Expression value),
- bool useIsSetField}) {
- assert(useIsSetField != null);
+ IsSetEncoding isSetEncoding}) {
+ assert(isSetEncoding != null);
Expression exception = new Throw(new ConstructorInvocation(
coreTypes.lateInitializationErrorConstructor,
new Arguments(<Expression>[
@@ -349,49 +458,132 @@
}
}
- if (useIsSetField) {
- // Generate:
- //
- // if (_#isSet#field) {
- // throw '...';
- // } else
- // _#isSet#field = true;
- // return _#field = parameter
- // }
- return new IfStatement(
- createIsSetRead()..fileOffset = fileOffset,
+ switch (isSetEncoding) {
+ case IsSetEncoding.useIsSetField:
+ // Generate:
+ //
+ // if (_#isSet#field) {
+ // throw '...';
+ // } else
+ // _#isSet#field = true;
+ // return _#field = parameter
+ // }
+ return new IfStatement(
+ createIsSetRead()..fileOffset = fileOffset,
+ new ExpressionStatement(exception)..fileOffset = fileOffset,
+ new Block([
+ new ExpressionStatement(
+ createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createReturn(createVariableWrite(
+ new VariableGet(parameter)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset)
+ ])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
+ case IsSetEncoding.useSentinel:
+ // Generate:
+ //
+ // if (isSentinel(_#field)) {
+ // return _#field = parameter;
+ // } else {
+ // throw '...';
+ // }
+ return new IfStatement(
+ new StaticInvocation(
+ coreTypes.isSentinelMethod,
+ new Arguments(
+ <Expression>[createVariableRead()..fileOffset = fileOffset])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createReturn(createVariableWrite(
+ new VariableGet(parameter)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset),
new ExpressionStatement(exception)..fileOffset = fileOffset,
- new Block([
- new ExpressionStatement(
- createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- createReturn(createVariableWrite(
- new VariableGet(parameter)..fileOffset = fileOffset)
- ..fileOffset = fileOffset)
- ])
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset;
- } else {
- // Generate:
- //
- // if (_#field == null) {
- // return _#field = parameter;
- // } else {
- // throw '...';
- // }
- return new IfStatement(
- new MethodInvocation(
- createVariableRead()..fileOffset = fileOffset,
- equalsName,
- new Arguments(
- <Expression>[new NullLiteral()..fileOffset = fileOffset])
- ..fileOffset = fileOffset)
- ..fileOffset = fileOffset,
- createReturn(createVariableWrite(
- new VariableGet(parameter)..fileOffset = fileOffset)
- ..fileOffset = fileOffset),
- new ExpressionStatement(exception)..fileOffset = fileOffset,
- )..fileOffset = fileOffset;
+ )..fileOffset = fileOffset;
+ case IsSetEncoding.useNull:
+ // Generate:
+ //
+ // if (_#field == null) {
+ // return _#field = parameter;
+ // } else {
+ // throw '...';
+ // }
+ return new IfStatement(
+ new MethodInvocation(
+ createVariableRead()..fileOffset = fileOffset,
+ equalsName,
+ new Arguments(
+ <Expression>[new NullLiteral()..fileOffset = fileOffset])
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
+ createReturn(createVariableWrite(
+ new VariableGet(parameter)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset),
+ new ExpressionStatement(exception)..fileOffset = fileOffset,
+ )..fileOffset = fileOffset;
}
+ throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
+}
+
+/// Strategies for encoding whether a late field/local has been initialized.
+enum IsSetEncoding {
+ /// Use a boolean `isSet` field/local.
+ useIsSetField,
+
+ /// Use `null` as sentinel value to signal an uninitialized field/locals.
+ useNull,
+
+ /// Use `createSentinel`and `isSentinel` from `dart:_internal` to generate
+ /// and check a sentinel value to signal an uninitialized field/local.
+ useSentinel,
+}
+
+/// Strategies for encoding of late fields and locals.
+enum IsSetStrategy {
+ /// Always is use an `isSet` field/local to track whether the field/local has
+ /// been initialized.
+ forceUseIsSetField,
+
+ /// For potentially nullable fields/locals use an `isSet` field/local to track
+ /// whether the field/local has been initialized. Otherwise use `null` as
+ /// sentinel value to signal an uninitialized field/local.
+ ///
+ /// This strategy can only be used with sound null safety mode. In weak mode
+ /// non-nullable can be assigned `null` from legacy code and therefore `null`
+ /// doesn't work as a sentinel.
+ useIsSetFieldOrNull,
+
+ /// For potentially nullable fields/locals use `createSentinel`and
+ /// `isSentinel` from `dart:_internal` to generate and check a sentinel value
+ /// to signal an uninitialized field/local. Otherwise use `null` as
+ /// sentinel value to signal an uninitialized field/local.
+ useSentinelOrNull,
+}
+
+IsSetStrategy computeIsSetStrategy(SourceLibraryBuilder libraryBuilder) {
+ IsSetStrategy isSetStrategy = IsSetStrategy.useIsSetFieldOrNull;
+ if (libraryBuilder.loader.target.backendTarget.supportsLateLoweringSentinel) {
+ isSetStrategy = IsSetStrategy.useSentinelOrNull;
+ } else if (libraryBuilder.loader.nnbdMode != NnbdMode.Strong) {
+ isSetStrategy = IsSetStrategy.forceUseIsSetField;
+ }
+ return isSetStrategy;
+}
+
+IsSetEncoding computeIsSetEncoding(DartType type, IsSetStrategy isSetStrategy) {
+ switch (isSetStrategy) {
+ case IsSetStrategy.forceUseIsSetField:
+ return IsSetEncoding.useIsSetField;
+ case IsSetStrategy.useIsSetFieldOrNull:
+ return type.isPotentiallyNullable
+ ? IsSetEncoding.useIsSetField
+ : IsSetEncoding.useNull;
+ case IsSetStrategy.useSentinelOrNull:
+ return type.isPotentiallyNullable
+ ? IsSetEncoding.useSentinel
+ : IsSetEncoding.useNull;
+ }
+ throw new UnsupportedError("Unexpected IsSetStrategy $isSetStrategy");
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index a75173f..0fc4c97 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -37,8 +37,6 @@
import '../kernel/forest.dart';
-import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
-
import '../kernel/kernel_builder.dart'
show ClassHierarchyBuilder, ImplicitFieldType;
@@ -284,14 +282,6 @@
}
@override
- bool isLocalVariableWithoutDeclaredType(VariableDeclaration variable) {
- return variable is VariableDeclarationImpl &&
- variable.parent is Statement &&
- variable.isImplicitlyTyped &&
- !variable.hasDeclaredInitializer;
- }
-
- @override
bool isNever(DartType type) {
return typeEnvironment.coreTypes.isBottom(type);
}
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 3844240..2db105d 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -334,6 +334,8 @@
FinalAndCovariant/part_wrapped_script2: Fail
FinalAndCovariant/script2: Fail
FinalFieldWithoutInitializer/example: Fail
+FinalNotAssignedError/script: Fail # Fasta reports too many errors
+FinalNotAssignedError/part_wrapped_script: Fail # Fasta reports too many errors
ForInLoopElementTypeNotAssignable/example: Fail
ForInLoopExactlyOneVariable/analyzerCode: Fail # The analyzer doesn't recover well.
ForInLoopExactlyOneVariable/part_wrapped_statement: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index c77266e..4adf914 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4195,6 +4195,19 @@
T t; t;
}
+FinalNotAssignedError:
+ template: "Final variable '#name' must be assigned before it can be used."
+ analyzerCode: READ_POTENTIALLY_UNASSIGNED_FINAL
+ configuration: nnbd-strong
+ script: >
+ method(bool b) {
+ final int i;
+ if (b) {
+ i = 0;
+ }
+ i;
+ }
+
NonNullableLateDefinitelyUnassignedError:
template: "Non-nullable late variable '#name' without initializer is definitely unassigned."
configuration: nnbd-strong
diff --git a/pkg/front_end/test/comments_on_certain_arguments_tool.dart b/pkg/front_end/test/comments_on_certain_arguments_tool.dart
index 5920035..c0ff2cb 100644
--- a/pkg/front_end/test/comments_on_certain_arguments_tool.dart
+++ b/pkg/front_end/test/comments_on_certain_arguments_tool.dart
@@ -4,16 +4,7 @@
import 'dart:convert' show utf8;
import 'dart:io'
- show
- Directory,
- File,
- FileSystemEntity,
- Platform,
- Process,
- ProcessResult,
- exitCode,
- stdin,
- stdout;
+ show Directory, File, FileSystemEntity, exitCode, stdin, stdout;
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
@@ -41,16 +32,9 @@
import 'package:kernel/target/targets.dart' show TargetFlags;
import "package:vm/target/vm.dart" show VmTarget;
-final Uri repoDir = _computeRepoDir();
+import "utils/io_utils.dart";
-Uri _computeRepoDir() {
- ProcessResult result = Process.runSync(
- 'git', ['rev-parse', '--show-toplevel'],
- runInShell: true,
- workingDirectory: new File.fromUri(Platform.script).parent.path);
- String dirPath = (result.stdout as String).trim();
- return new Directory(dirPath).uri;
-}
+final Uri repoDir = computeRepoDirUri();
Set<Uri> libUris = {};
diff --git a/pkg/front_end/test/explicit_creation_test.dart b/pkg/front_end/test/explicit_creation_test.dart
index 215f824..7e8246a 100644
--- a/pkg/front_end/test/explicit_creation_test.dart
+++ b/pkg/front_end/test/explicit_creation_test.dart
@@ -40,17 +40,9 @@
import "package:vm/target/vm.dart" show VmTarget;
import 'testing_utils.dart' show getGitFiles;
+import "utils/io_utils.dart";
-final Uri repoDir = _computeRepoDir();
-
-Uri _computeRepoDir() {
- ProcessResult result = Process.runSync(
- 'git', ['rev-parse', '--show-toplevel'],
- runInShell: true,
- workingDirectory: new File.fromUri(Platform.script).parent.path);
- String dirPath = (result.stdout as String).trim();
- return new Directory(dirPath).uri;
-}
+final Uri repoDir = computeRepoDirUri();
Set<Uri> libUris = {};
diff --git a/pkg/front_end/test/fasta/messages_suite.dart b/pkg/front_end/test/fasta/messages_suite.dart
index cb0f930..3a3dcd2 100644
--- a/pkg/front_end/test/fasta/messages_suite.dart
+++ b/pkg/front_end/test/fasta/messages_suite.dart
@@ -6,7 +6,7 @@
import "dart:convert" show utf8;
-import "dart:io" show File;
+import 'dart:io' show File, Platform;
import "dart:typed_data" show Uint8List;
@@ -97,8 +97,31 @@
final BatchCompiler compiler;
final bool fastOnly;
+ final bool interactive;
- MessageTestSuite(this.fastOnly)
+ final Set<String> reportedWords = {};
+ final Set<String> reportedWordsDenylisted = {};
+
+ @override
+ Future<void> postRun() {
+ String dartPath = Platform.resolvedExecutable;
+ Uri suiteUri =
+ spell.repoDir.resolve("pkg/front_end/test/fasta/messages_suite.dart");
+ File suiteFile = new File.fromUri(suiteUri).absolute;
+ if (!suiteFile.existsSync()) {
+ throw "Specified suite path is invalid.";
+ }
+ String suitePath = suiteFile.path;
+ spell.spellSummarizeAndInteractiveMode(
+ reportedWords,
+ reportedWordsDenylisted,
+ [spell.Dictionaries.cfeMessages],
+ interactive,
+ '"$dartPath" "$suitePath" -DfastOnly=true -Dinteractive=true');
+ return null;
+ }
+
+ MessageTestSuite(this.fastOnly, this.interactive)
: fileSystem = new MemoryFileSystem(Uri.parse("org-dartlang-fasta:///")),
compiler = new BatchCompiler(null);
@@ -143,8 +166,8 @@
Configuration configuration;
Source source;
- List<String> formatSpellingMistakes(
- spell.SpellingResult spellResult, int offset, String message) {
+ List<String> formatSpellingMistakes(spell.SpellingResult spellResult,
+ int offset, String message, String messageForDenyListed) {
if (source == null) {
List<int> bytes = file.readAsBytesSync();
List<int> lineStarts = new List<int>();
@@ -160,12 +183,20 @@
for (int i = 0; i < spellResult.misspelledWords.length; i++) {
Location location = source.getLocation(
uri, offset + spellResult.misspelledWordsOffset[i]);
+ bool denylisted = spellResult.misspelledWordsDenylisted[i];
+ String messageToUse = message;
+ if (denylisted) {
+ messageToUse = messageForDenyListed;
+ reportedWordsDenylisted.add(spellResult.misspelledWords[i]);
+ } else {
+ reportedWords.add(spellResult.misspelledWords[i]);
+ }
result.add(command_line_reporting.formatErrorMessage(
source.getTextLine(location.line),
location,
spellResult.misspelledWords[i].length,
relativize(uri),
- "$message: '${spellResult.misspelledWords[i]}'."));
+ "$messageToUse: '${spellResult.misspelledWords[i]}'."));
}
return result;
}
@@ -190,7 +221,10 @@
spellingMessages.addAll(formatSpellingMistakes(
spellingResult,
node.span.start.offset,
- "Template likely has the following spelling mistake"));
+ "Template has the following word that is "
+ "not in our dictionary",
+ "Template has the following word that is "
+ "on our deny-list"));
}
break;
@@ -206,7 +240,10 @@
spellingMessages.addAll(formatSpellingMistakes(
spellingResult,
node.span.start.offset,
- "Tip likely has the following spelling mistake"));
+ "Tip has the following word that is "
+ "not in our dictionary",
+ "Tip has the following word that is "
+ "on our deny-list"));
}
break;
@@ -745,7 +782,8 @@
Future<MessageTestSuite> createContext(
Chain suite, Map<String, String> environment) async {
final bool fastOnly = environment["fastOnly"] == "true";
- return new MessageTestSuite(fastOnly);
+ final bool interactive = environment["interactive"] == "true";
+ return new MessageTestSuite(fastOnly, interactive);
}
String relativize(Uri uri) {
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 2905b1b..b18d9c2 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -162,6 +162,7 @@
class FolderOptions {
final Map<ExperimentalFlag, bool> _experimentalFlags;
final bool forceLateLowering;
+ final bool forceLateLoweringSentinel;
final bool forceStaticFieldLowering;
final bool forceNoExplicitGetterCalls;
final bool nnbdAgnosticMode;
@@ -170,6 +171,7 @@
FolderOptions(this._experimentalFlags,
{this.forceLateLowering: false,
+ this.forceLateLoweringSentinel: false,
this.forceStaticFieldLowering: false,
this.forceNoExplicitGetterCalls: false,
this.nnbdAgnosticMode: false,
@@ -177,6 +179,7 @@
// can be null
this.overwriteCurrentSdkVersion})
: assert(forceLateLowering != null),
+ assert(forceLateLoweringSentinel != null),
assert(forceStaticFieldLowering != null),
assert(forceNoExplicitGetterCalls != null),
assert(nnbdAgnosticMode != null),
@@ -317,6 +320,7 @@
FolderOptions folderOptions = _folderOptions[directory.uri];
if (folderOptions == null) {
bool forceLateLowering = false;
+ bool forceLateLoweringSentinel = false;
bool forceStaticFieldLowering = false;
bool forceNoExplicitGetterCalls = false;
bool nnbdAgnosticMode = false;
@@ -324,6 +328,7 @@
if (directory.uri == baseUri) {
folderOptions = new FolderOptions({},
forceLateLowering: forceLateLowering,
+ forceLateLoweringSentinel: forceLateLoweringSentinel,
forceStaticFieldLowering: forceStaticFieldLowering,
forceNoExplicitGetterCalls: forceNoExplicitGetterCalls,
nnbdAgnosticMode: nnbdAgnosticMode,
@@ -342,6 +347,8 @@
} else if (line.startsWith(overwriteCurrentSdkVersion)) {
overwriteCurrentSdkVersionArgument =
line.substring(overwriteCurrentSdkVersion.length);
+ } else if (line.startsWith(Flags.forceLateLoweringSentinel)) {
+ forceLateLoweringSentinel = true;
} else if (line.startsWith(Flags.forceLateLowering)) {
forceLateLowering = true;
} else if (line.startsWith(Flags.forceStaticFieldLowering)) {
@@ -367,6 +374,7 @@
onWarning: (String message) =>
throw new ArgumentError(message)),
forceLateLowering: forceLateLowering,
+ forceLateLoweringSentinel: forceLateLoweringSentinel,
forceStaticFieldLowering: forceStaticFieldLowering,
forceNoExplicitGetterCalls: forceNoExplicitGetterCalls,
nnbdAgnosticMode: nnbdAgnosticMode,
@@ -839,6 +847,8 @@
await context.computeUriTranslator(description);
TargetFlags targetFlags = new TargetFlags(
forceLateLoweringForTesting: testOptions.forceLateLowering,
+ forceLateLoweringSentinelForTesting:
+ testOptions.forceLateLoweringSentinel,
forceStaticFieldLoweringForTesting: testOptions.forceStaticFieldLowering,
forceNoExplicitGetterCallsForTesting:
testOptions.forceNoExplicitGetterCalls,
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 6b94883..5985a19 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -1036,6 +1036,7 @@
stdout
stmt
str
+strategies
streak
streaming
strict
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 519403a..5aa5116 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -351,6 +351,7 @@
ko
koo
la
+launch
launching
le
legs
diff --git a/pkg/front_end/test/spell_checking_utils.dart b/pkg/front_end/test/spell_checking_utils.dart
index e29b233..948ea88 100644
--- a/pkg/front_end/test/spell_checking_utils.dart
+++ b/pkg/front_end/test/spell_checking_utils.dart
@@ -2,7 +2,11 @@
// 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 'dart:io';
+import 'dart:io' show File, stdin, stdout;
+
+import "utils/io_utils.dart";
+
+final Uri repoDir = computeRepoDirUri();
enum Dictionaries {
common,
@@ -162,19 +166,18 @@
Uri dictionaryToUri(Dictionaries dictionaryType) {
switch (dictionaryType) {
case Dictionaries.common:
- return Uri.base
+ return repoDir
.resolve("pkg/front_end/test/spell_checking_list_common.txt");
case Dictionaries.cfeMessages:
- return Uri.base
+ return repoDir
.resolve("pkg/front_end/test/spell_checking_list_messages.txt");
case Dictionaries.cfeCode:
- return Uri.base
- .resolve("pkg/front_end/test/spell_checking_list_code.txt");
+ return repoDir.resolve("pkg/front_end/test/spell_checking_list_code.txt");
case Dictionaries.cfeTests:
- return Uri.base
+ return repoDir
.resolve("pkg/front_end/test/spell_checking_list_tests.txt");
case Dictionaries.denylist:
- return Uri.base
+ return repoDir
.resolve("pkg/front_end/test/spell_checking_list_denylist.txt");
}
throw "Unknown Dictionary";
@@ -342,3 +345,121 @@
}
return result;
}
+
+void spellSummarizeAndInteractiveMode(
+ Set<String> reportedWords,
+ Set<String> reportedWordsDenylisted,
+ List<Dictionaries> dictionaries,
+ bool interactive,
+ String interactiveLaunchExample) {
+ if (reportedWordsDenylisted.isNotEmpty) {
+ print("\n\n\n");
+ print("================");
+ print("The following words was reported as used and denylisted:");
+ print("----------------");
+ for (String s in reportedWordsDenylisted) {
+ print("$s");
+ }
+ print("================");
+ }
+ if (reportedWords.isNotEmpty) {
+ print("\n\n\n");
+ print("================");
+ print("The following word(s) were reported as unknown:");
+ print("----------------");
+
+ Dictionaries dictionaryToUse;
+ if (dictionaries.contains(Dictionaries.cfeTests)) {
+ dictionaryToUse = Dictionaries.cfeTests;
+ } else if (dictionaries.contains(Dictionaries.cfeMessages)) {
+ dictionaryToUse = Dictionaries.cfeMessages;
+ } else if (dictionaries.contains(Dictionaries.cfeCode)) {
+ dictionaryToUse = Dictionaries.cfeCode;
+ } else {
+ for (Dictionaries dictionary in dictionaries) {
+ if (dictionaryToUse == null ||
+ dictionary.index < dictionaryToUse.index) {
+ dictionaryToUse = dictionary;
+ }
+ }
+ }
+
+ if (interactive && dictionaryToUse != null) {
+ List<String> addedWords = new List<String>();
+ for (String s in reportedWords) {
+ print("- $s");
+ String answer;
+ bool add;
+ while (true) {
+ stdout.write("Do you want to add the word to the dictionary "
+ "$dictionaryToUse (y/n)? ");
+ answer = stdin.readLineSync().trim().toLowerCase();
+ switch (answer) {
+ case "y":
+ case "yes":
+ case "true":
+ add = true;
+ break;
+ case "n":
+ case "no":
+ case "false":
+ add = false;
+ break;
+ default:
+ add = null;
+ print("'$answer' is not a valid answer. Please try again.");
+ break;
+ }
+ if (add != null) break;
+ }
+ if (add) {
+ addedWords.add(s);
+ }
+ }
+ if (addedWords.isNotEmpty) {
+ File dictionaryFile =
+ new File.fromUri(dictionaryToUri(dictionaryToUse));
+ List<String> lines = dictionaryFile.readAsLinesSync();
+ List<String> header = new List<String>();
+ List<String> sortThis = new List<String>();
+ for (String line in lines) {
+ if (line.startsWith("#")) {
+ header.add(line);
+ } else if (line.trim().isEmpty && sortThis.isEmpty) {
+ header.add(line);
+ } else if (line.trim().isNotEmpty) {
+ sortThis.add(line);
+ }
+ }
+ sortThis.addAll(addedWords);
+ sortThis.sort();
+ lines = new List<String>();
+ lines.addAll(header);
+ if (header.isEmpty || header.last.isNotEmpty) {
+ lines.add("");
+ }
+ lines.addAll(sortThis);
+ lines.add("");
+ dictionaryFile.writeAsStringSync(lines.join("\n"));
+ }
+ } else {
+ for (String s in reportedWords) {
+ print("$s");
+ }
+ if (dictionaries.isNotEmpty) {
+ print("----------------");
+ print("If the word(s) are correctly spelled please add it to one of "
+ "these files:");
+ for (Dictionaries dictionary in dictionaries) {
+ print(" - ${dictionaryToUri(dictionary)}");
+ }
+
+ print("");
+ print("To add words easily, try to run this script in interactive "
+ "mode via the command");
+ print(interactiveLaunchExample);
+ }
+ }
+ print("================");
+ }
+}
diff --git a/pkg/front_end/test/spelling_test_base.dart b/pkg/front_end/test/spelling_test_base.dart
index 9879c8c..9bafa38 100644
--- a/pkg/front_end/test/spelling_test_base.dart
+++ b/pkg/front_end/test/spelling_test_base.dart
@@ -4,7 +4,7 @@
import 'dart:async' show Future;
-import 'dart:io' show File, Platform, stdin, stdout;
+import 'dart:io' show File, Platform;
import 'dart:typed_data' show Uint8List;
@@ -51,6 +51,8 @@
bool get onlyDenylisted;
+ String get repoRelativeSuitePath;
+
Set<String> reportedWords = {};
Set<String> reportedWordsDenylisted = {};
@@ -61,111 +63,19 @@
@override
Future<void> postRun() {
- if (reportedWordsDenylisted.isNotEmpty) {
- print("\n\n\n");
- print("================");
- print("The following words was reported as used and denylisted:");
- print("----------------");
- for (String s in reportedWordsDenylisted) {
- print("$s");
- }
- print("================");
+ String dartPath = Platform.resolvedExecutable;
+ Uri suiteUri = spell.repoDir.resolve(repoRelativeSuitePath);
+ File suiteFile = new File.fromUri(suiteUri).absolute;
+ if (!suiteFile.existsSync()) {
+ throw "Specified suite path is invalid.";
}
- if (reportedWords.isNotEmpty) {
- print("\n\n\n");
- print("================");
- print("The following word(s) were reported as unknown:");
- print("----------------");
-
- spell.Dictionaries dictionaryToUse;
- if (dictionaries.contains(spell.Dictionaries.cfeTests)) {
- dictionaryToUse = spell.Dictionaries.cfeTests;
- } else if (dictionaries.contains(spell.Dictionaries.cfeMessages)) {
- dictionaryToUse = spell.Dictionaries.cfeMessages;
- } else if (dictionaries.contains(spell.Dictionaries.cfeCode)) {
- dictionaryToUse = spell.Dictionaries.cfeCode;
- } else {
- for (spell.Dictionaries dictionary in dictionaries) {
- if (dictionaryToUse == null ||
- dictionary.index < dictionaryToUse.index) {
- dictionaryToUse = dictionary;
- }
- }
- }
-
- if (interactive && dictionaryToUse != null) {
- List<String> addedWords = new List<String>();
- for (String s in reportedWords) {
- print("- $s");
- stdout.write("Do you want to add the word to the dictionary "
- "$dictionaryToUse (y/n)? ");
- String answer = stdin.readLineSync().trim().toLowerCase();
- bool add;
- switch (answer) {
- case "y":
- case "yes":
- case "true":
- add = true;
- break;
- case "n":
- case "no":
- case "false":
- add = false;
- break;
- default:
- throw "Didn't understand '$answer'";
- }
- if (add) {
- addedWords.add(s);
- }
- }
- if (addedWords.isNotEmpty) {
- File dictionaryFile =
- new File.fromUri(spell.dictionaryToUri(dictionaryToUse));
- List<String> lines = dictionaryFile.readAsLinesSync();
- List<String> header = new List<String>();
- List<String> sortThis = new List<String>();
- for (String line in lines) {
- if (line.startsWith("#")) {
- header.add(line);
- } else if (line.trim().isEmpty && sortThis.isEmpty) {
- header.add(line);
- } else if (line.trim().isNotEmpty) {
- sortThis.add(line);
- }
- }
- sortThis.addAll(addedWords);
- sortThis.sort();
- lines = new List<String>();
- lines.addAll(header);
- if (header.isEmpty || header.last.isNotEmpty) {
- lines.add("");
- }
- lines.addAll(sortThis);
- lines.add("");
- dictionaryFile.writeAsStringSync(lines.join("\n"));
- }
- } else {
- for (String s in reportedWords) {
- print("$s");
- }
- if (dictionaries.isNotEmpty) {
- print("----------------");
- print("If the word(s) are correctly spelled please add it to one of "
- "these files:");
- for (spell.Dictionaries dictionary in dictionaries) {
- print(" - ${spell.dictionaryToUri(dictionary)}");
- }
-
- print("");
- print("To add words easily, try to run this script in interactive "
- "mode via the command");
- print("dart ${Platform.script.toFilePath()} "
- "-DonlyInGit=$onlyInGit -Dinteractive=true");
- }
- }
- print("================");
- }
+ String suitePath = suiteFile.path;
+ spell.spellSummarizeAndInteractiveMode(
+ reportedWords,
+ reportedWordsDenylisted,
+ dictionaries,
+ interactive,
+ '"$dartPath" "$suitePath" -DonlyInGit=$onlyInGit -Dinteractive=true');
return null;
}
}
diff --git a/pkg/front_end/test/spelling_test_external_targets.dart b/pkg/front_end/test/spelling_test_external_targets.dart
index f339a46..0330b22 100644
--- a/pkg/front_end/test/spelling_test_external_targets.dart
+++ b/pkg/front_end/test/spelling_test_external_targets.dart
@@ -39,6 +39,10 @@
@override
bool get onlyDenylisted => true;
+ @override
+ String get repoRelativeSuitePath =>
+ "pkg/front_end/test/spelling_test_external_targets.dart";
+
Stream<TestDescription> list(Chain suite) async* {
for (String subdir in const ["pkg/", "sdk/"]) {
Directory testRoot = new Directory.fromUri(suite.uri.resolve(subdir));
diff --git a/pkg/front_end/test/spelling_test_not_src_suite.dart b/pkg/front_end/test/spelling_test_not_src_suite.dart
index 28d5262..3259c88 100644
--- a/pkg/front_end/test/spelling_test_not_src_suite.dart
+++ b/pkg/front_end/test/spelling_test_not_src_suite.dart
@@ -38,4 +38,8 @@
@override
bool get onlyDenylisted => false;
+
+ @override
+ String get repoRelativeSuitePath =>
+ "pkg/front_end/test/spelling_test_not_src_suite.dart";
}
diff --git a/pkg/front_end/test/spelling_test_src_suite.dart b/pkg/front_end/test/spelling_test_src_suite.dart
index 4fe9568..afea1e0 100644
--- a/pkg/front_end/test/spelling_test_src_suite.dart
+++ b/pkg/front_end/test/spelling_test_src_suite.dart
@@ -37,4 +37,8 @@
@override
bool get onlyDenylisted => false;
+
+ @override
+ String get repoRelativeSuitePath =>
+ "pkg/front_end/test/spelling_test_src_suite.dart";
}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
index 4747968..8784442 100644
--- a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
@@ -19,8 +19,16 @@
synthetic constructor •() → self::Class
: super core::Object::•()
;
- static get nonNullableStaticField() → core::int
- return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+ static get nonNullableStaticField() → core::int {
+ if(!self::Class::_#nonNullableStaticField#isSet) {
+ final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0;
+ if(self::Class::_#nonNullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticField = #t1;
+ self::Class::_#nonNullableStaticField#isSet = true;
+ }
+ return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+ }
static get nullableStaticField() → core::int? {
if(!self::Class::_#nullableStaticField#isSet) {
final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int} self::Class::nullableStaticField.{core::Object::hashCode} : 0;
@@ -31,8 +39,16 @@
}
return self::Class::_#nullableStaticField;
}
- get nonNullableInstanceField() → core::int
- return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+ get nonNullableInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+ final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0;
+ if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+ this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+ }
+ return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+ }
get nullableInstanceField() → core::int? {
if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} this.{self::Class::nullableInstanceField}.{core::Object::hashCode} : 0;
@@ -50,8 +66,16 @@
static field core::int nullableTopLevelFieldReads = 0;
static field core::int? _#nullableTopLevelField = null;
static field core::bool _#nullableTopLevelField#isSet = false;
-static get nonNullableTopLevelField() → core::int
- return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nonNullableTopLevelField() → core::int {
+ if(!self::_#nonNullableTopLevelField#isSet) {
+ final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0;
+ if(self::_#nonNullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+ self::_#nonNullableTopLevelField = #t15;
+ self::_#nonNullableTopLevelField#isSet = true;
+ }
+ return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
static get nullableTopLevelField() → core::int? {
if(!self::_#nullableTopLevelField#isSet) {
final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int} self::nullableTopLevelField.{core::Object::hashCode} : 0;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
index 4747968..8784442 100644
--- a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
@@ -19,8 +19,16 @@
synthetic constructor •() → self::Class
: super core::Object::•()
;
- static get nonNullableStaticField() → core::int
- return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+ static get nonNullableStaticField() → core::int {
+ if(!self::Class::_#nonNullableStaticField#isSet) {
+ final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0;
+ if(self::Class::_#nonNullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticField = #t1;
+ self::Class::_#nonNullableStaticField#isSet = true;
+ }
+ return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+ }
static get nullableStaticField() → core::int? {
if(!self::Class::_#nullableStaticField#isSet) {
final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int} self::Class::nullableStaticField.{core::Object::hashCode} : 0;
@@ -31,8 +39,16 @@
}
return self::Class::_#nullableStaticField;
}
- get nonNullableInstanceField() → core::int
- return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+ get nonNullableInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+ final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0;
+ if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+ this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+ }
+ return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+ }
get nullableInstanceField() → core::int? {
if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} this.{self::Class::nullableInstanceField}.{core::Object::hashCode} : 0;
@@ -50,8 +66,16 @@
static field core::int nullableTopLevelFieldReads = 0;
static field core::int? _#nullableTopLevelField = null;
static field core::bool _#nullableTopLevelField#isSet = false;
-static get nonNullableTopLevelField() → core::int
- return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nonNullableTopLevelField() → core::int {
+ if(!self::_#nonNullableTopLevelField#isSet) {
+ final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0;
+ if(self::_#nonNullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+ self::_#nonNullableTopLevelField = #t15;
+ self::_#nonNullableTopLevelField#isSet = true;
+ }
+ return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
static get nullableTopLevelField() → core::int? {
if(!self::_#nullableTopLevelField#isSet) {
final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int} self::nullableTopLevelField.{core::Object::hashCode} : 0;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart
new file mode 100644
index 0000000..2f01985
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2020, 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 'initializer_rewrite_from_opt_out_lib.dart';
+
+int nonNullableTopLevelFieldReads = 0;
+
+late final int nonNullableTopLevelField = nonNullableTopLevelFieldReads++ == 0
+ ? nonNullableTopLevelField
+ : computeInitialValue();
+
+int nullableTopLevelFieldReads = 0;
+
+late final int? nullableTopLevelField = nullableTopLevelFieldReads++ == 0
+ ? nullableTopLevelField
+ : computeInitialValue();
+
+class Class {
+ static int nonNullableStaticFieldReads = 0;
+
+ static late final int nonNullableStaticField =
+ nonNullableStaticFieldReads++ == 0
+ ? nonNullableStaticField
+ : computeInitialValue();
+
+ static int nullableStaticFieldReads = 0;
+
+ static late final int? nullableStaticField = nullableStaticFieldReads++ == 0
+ ? nullableStaticField
+ : computeInitialValue();
+
+ int nonNullableInstanceFieldReads = 0;
+
+ late final int nonNullableInstanceField = nonNullableInstanceFieldReads++ == 0
+ ? nonNullableInstanceField
+ : computeInitialValue();
+
+ int nullableInstanceFieldReads = 0;
+
+ late final int? nullableInstanceField = nullableInstanceFieldReads++ == 0
+ ? nullableInstanceField
+ : computeInitialValue();
+}
+
+void main() {
+ throws(() => nonNullableTopLevelField, "Read nonNullableTopLevelField");
+ throws(() => nullableTopLevelField, "Read nullableTopLevelField");
+ throws(() => Class.nonNullableStaticField, "Read nonNullableStaticField");
+ throws(() => Class.nullableStaticField, "Read nullableStaticField");
+ throws(() => new Class().nonNullableInstanceField,
+ "Read nonNullableInstanceField");
+ throws(() => new Class().nullableInstanceField, "Read nullableInstanceField");
+}
+
+throws(f(), String message) {
+ dynamic value;
+ try {
+ value = f();
+ } on LateInitializationError catch (e) {
+ print(e);
+ return;
+ }
+ throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.outline.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.outline.expect
new file mode 100644
index 0000000..7ddeb49
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.outline.expect
@@ -0,0 +1,49 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+ static field core::int nonNullableStaticFieldReads;
+ static field core::int? _#nonNullableStaticField;
+ static field core::int nullableStaticFieldReads;
+ static field core::int? _#nullableStaticField;
+ static field core::bool _#nullableStaticField#isSet;
+ field core::int nonNullableInstanceFieldReads;
+ field core::int? _#Class#nonNullableInstanceField;
+ field core::int nullableInstanceFieldReads;
+ field core::int? _#Class#nullableInstanceField;
+ field core::bool _#Class#nullableInstanceField#isSet;
+ synthetic constructor •() → self::Class
+ ;
+ static get nonNullableStaticField() → core::int;
+ static get nullableStaticField() → core::int?;
+ get nonNullableInstanceField() → core::int;
+ get nullableInstanceField() → core::int?;
+}
+static field core::int nonNullableTopLevelFieldReads;
+static field core::int? _#nonNullableTopLevelField;
+static field core::int nullableTopLevelFieldReads;
+static field core::int? _#nullableTopLevelField;
+static field core::bool _#nullableTopLevelField#isSet;
+static get nonNullableTopLevelField() → core::int;
+static get nullableTopLevelField() → core::int?;
+static method main() → void
+ ;
+static method throws(() → dynamic f, core::String message) → dynamic
+ ;
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.8
+// ^^^^^^^^^^^^
+//
+import self as self2;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int
+ ;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.expect
new file mode 100644
index 0000000..2a73d8e
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.expect
@@ -0,0 +1,103 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+ static field core::int nonNullableStaticFieldReads = 0;
+ static field core::int? _#nonNullableStaticField = null;
+ static field core::int nullableStaticFieldReads = 0;
+ static field core::int? _#nullableStaticField = null;
+ static field core::bool _#nullableStaticField#isSet = false;
+ field core::int nonNullableInstanceFieldReads = 0;
+ field core::int? _#Class#nonNullableInstanceField = null;
+ field core::int nullableInstanceFieldReads = 0;
+ field core::int? _#Class#nullableInstanceField = null;
+ field core::bool _#Class#nullableInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get nonNullableStaticField() → core::int
+ return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField : ini::computeInitialValue() in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+ static get nullableStaticField() → core::int? {
+ if(!self::Class::_#nullableStaticField#isSet) {
+ final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+ if(self::Class::_#nullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+ self::Class::_#nullableStaticField = #t5;
+ self::Class::_#nullableStaticField#isSet = true;
+ }
+ return self::Class::_#nullableStaticField;
+ }
+ get nonNullableInstanceField() → core::int
+ return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue() in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+ get nullableInstanceField() → core::int? {
+ if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+ final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+ if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nullableInstanceField} = #t12;
+ this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+ }
+ return this.{self::Class::_#Class#nullableInstanceField};
+ }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+ return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField : ini::computeInitialValue() in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+ if(!self::_#nullableTopLevelField#isSet) {
+ final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+ if(self::_#nullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+ self::_#nullableTopLevelField = #t19;
+ self::_#nullableTopLevelField#isSet = true;
+ }
+ return self::_#nullableTopLevelField;
+}
+static method main() → void {
+ self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+ self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+ self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+ self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+ self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+ self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+ dynamic value;
+ try {
+ value = f.call();
+ }
+ on core::LateInitializationError catch(final core::LateInitializationError e) {
+ core::print(e);
+ return;
+ }
+ throw "${message}: ${value}";
+}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.8
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+// int computeInitialValue() => null;
+// ^
+//
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int
+ return let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+int computeInitialValue() => null;
+ ^" in null as{TypeError,ForNonNullableByDefault} core::int;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.transformed.expect
new file mode 100644
index 0000000..e653691
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.transformed.expect
@@ -0,0 +1,103 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+ static field core::int nonNullableStaticFieldReads = 0;
+ static field core::int? _#nonNullableStaticField = null;
+ static field core::int nullableStaticFieldReads = 0;
+ static field core::int? _#nullableStaticField = null;
+ static field core::bool _#nullableStaticField#isSet = false;
+ field core::int nonNullableInstanceFieldReads = 0;
+ field core::int? _#Class#nonNullableInstanceField = null;
+ field core::int nullableInstanceFieldReads = 0;
+ field core::int? _#Class#nullableInstanceField = null;
+ field core::bool _#Class#nullableInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get nonNullableStaticField() → core::int
+ return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField : ini::computeInitialValue() in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+ static get nullableStaticField() → core::int? {
+ if(!self::Class::_#nullableStaticField#isSet) {
+ final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+ if(self::Class::_#nullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+ self::Class::_#nullableStaticField = #t5;
+ self::Class::_#nullableStaticField#isSet = true;
+ }
+ return self::Class::_#nullableStaticField;
+ }
+ get nonNullableInstanceField() → core::int
+ return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue() in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+ get nullableInstanceField() → core::int? {
+ if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+ final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+ if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nullableInstanceField} = #t12;
+ this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+ }
+ return this.{self::Class::_#Class#nullableInstanceField};
+ }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+ return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField : ini::computeInitialValue() in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+ if(!self::_#nullableTopLevelField#isSet) {
+ final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+ if(self::_#nullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+ self::_#nullableTopLevelField = #t19;
+ self::_#nullableTopLevelField#isSet = true;
+ }
+ return self::_#nullableTopLevelField;
+}
+static method main() → void {
+ self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+ self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+ self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+ self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+ self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+ self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+ dynamic value;
+ try {
+ value = f.call();
+ }
+ on core::LateInitializationError catch(final core::LateInitializationError e) {
+ core::print(e);
+ return;
+ }
+ throw "${message}: ${value}";
+}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.8
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+// int computeInitialValue() => null;
+// ^
+//
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int
+ return let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+int computeInitialValue() => null;
+ ^" in let core::Null? #t23 = null in #t23.==(null) ?{core::int} #t23 as{TypeError,ForNonNullableByDefault} core::int : #t23{core::int};
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.textual_outline.expect
new file mode 100644
index 0000000..181da77
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.textual_outline.expect
@@ -0,0 +1,23 @@
+import 'initializer_rewrite_from_opt_out_lib.dart';
+int nonNullableTopLevelFieldReads = 0;
+late ;
+final int nonNullableTopLevelField = nonNullableTopLevelFieldReads++ == 0 ? nonNullableTopLevelField : computeInitialValue();
+int nullableTopLevelFieldReads = 0;
+late ;
+final int? nullableTopLevelField = nullableTopLevelFieldReads++ == 0 ? nullableTopLevelField : computeInitialValue();
+class Class {
+ static int nonNullableStaticFieldReads = 0;
+ static late ;
+ final int nonNullableStaticField = nonNullableStaticFieldReads++ == 0 ? nonNullableStaticField : computeInitialValue();
+ static int nullableStaticFieldReads = 0;
+ static late ;
+ final int? nullableStaticField = nullableStaticFieldReads++ == 0 ? nullableStaticField : computeInitialValue();
+ int nonNullableInstanceFieldReads = 0;
+ late ;
+ final int nonNullableInstanceField = nonNullableInstanceFieldReads++ == 0 ? nonNullableInstanceField : computeInitialValue();
+ int nullableInstanceFieldReads = 0;
+ late ;
+ final int? nullableInstanceField = nullableInstanceFieldReads++ == 0 ? nullableInstanceField : computeInitialValue();
+}
+void main() {}
+throws(f(), String message) {}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.expect
new file mode 100644
index 0000000..d58daaa
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.expect
@@ -0,0 +1,117 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+ static field core::int nonNullableStaticFieldReads = 0;
+ static field core::int? _#nonNullableStaticField = null;
+ static field core::bool _#nonNullableStaticField#isSet = false;
+ static field core::int nullableStaticFieldReads = 0;
+ static field core::int? _#nullableStaticField = null;
+ static field core::bool _#nullableStaticField#isSet = false;
+ field core::int nonNullableInstanceFieldReads = 0;
+ field core::int? _#Class#nonNullableInstanceField = null;
+ field core::bool _#Class#nonNullableInstanceField#isSet = false;
+ field core::int nullableInstanceFieldReads = 0;
+ field core::int? _#Class#nullableInstanceField = null;
+ field core::bool _#Class#nullableInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get nonNullableStaticField() → core::int {
+ if(!self::Class::_#nonNullableStaticField#isSet) {
+ final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int*} self::Class::nonNullableStaticField : ini::computeInitialValue();
+ if(self::Class::_#nonNullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticField = #t1;
+ self::Class::_#nonNullableStaticField#isSet = true;
+ }
+ return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+ }
+ static get nullableStaticField() → core::int? {
+ if(!self::Class::_#nullableStaticField#isSet) {
+ final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+ if(self::Class::_#nullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+ self::Class::_#nullableStaticField = #t5;
+ self::Class::_#nullableStaticField#isSet = true;
+ }
+ return self::Class::_#nullableStaticField;
+ }
+ get nonNullableInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+ final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int*} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue();
+ if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+ this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+ }
+ return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+ }
+ get nullableInstanceField() → core::int? {
+ if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+ final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+ if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nullableInstanceField} = #t12;
+ this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+ }
+ return this.{self::Class::_#Class#nullableInstanceField};
+ }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::bool _#nonNullableTopLevelField#isSet = false;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int {
+ if(!self::_#nonNullableTopLevelField#isSet) {
+ final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int*} self::nonNullableTopLevelField : ini::computeInitialValue();
+ if(self::_#nonNullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+ self::_#nonNullableTopLevelField = #t15;
+ self::_#nonNullableTopLevelField#isSet = true;
+ }
+ return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
+static get nullableTopLevelField() → core::int? {
+ if(!self::_#nullableTopLevelField#isSet) {
+ final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+ if(self::_#nullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+ self::_#nullableTopLevelField = #t19;
+ self::_#nullableTopLevelField#isSet = true;
+ }
+ return self::_#nullableTopLevelField;
+}
+static method main() → void {
+ self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+ self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+ self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+ self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+ self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+ self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+ dynamic value;
+ try {
+ value = f.call();
+ }
+ on core::LateInitializationError catch(final core::LateInitializationError e) {
+ core::print(e);
+ return;
+ }
+ throw "${message}: ${value}";
+}
+
+library;
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int*
+ return null;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.transformed.expect
new file mode 100644
index 0000000..d58daaa
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.transformed.expect
@@ -0,0 +1,117 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+ static field core::int nonNullableStaticFieldReads = 0;
+ static field core::int? _#nonNullableStaticField = null;
+ static field core::bool _#nonNullableStaticField#isSet = false;
+ static field core::int nullableStaticFieldReads = 0;
+ static field core::int? _#nullableStaticField = null;
+ static field core::bool _#nullableStaticField#isSet = false;
+ field core::int nonNullableInstanceFieldReads = 0;
+ field core::int? _#Class#nonNullableInstanceField = null;
+ field core::bool _#Class#nonNullableInstanceField#isSet = false;
+ field core::int nullableInstanceFieldReads = 0;
+ field core::int? _#Class#nullableInstanceField = null;
+ field core::bool _#Class#nullableInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get nonNullableStaticField() → core::int {
+ if(!self::Class::_#nonNullableStaticField#isSet) {
+ final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int*} self::Class::nonNullableStaticField : ini::computeInitialValue();
+ if(self::Class::_#nonNullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticField = #t1;
+ self::Class::_#nonNullableStaticField#isSet = true;
+ }
+ return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+ }
+ static get nullableStaticField() → core::int? {
+ if(!self::Class::_#nullableStaticField#isSet) {
+ final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+ if(self::Class::_#nullableStaticField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+ self::Class::_#nullableStaticField = #t5;
+ self::Class::_#nullableStaticField#isSet = true;
+ }
+ return self::Class::_#nullableStaticField;
+ }
+ get nonNullableInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+ final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int*} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue();
+ if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+ this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+ }
+ return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+ }
+ get nullableInstanceField() → core::int? {
+ if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+ final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+ if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#nullableInstanceField} = #t12;
+ this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+ }
+ return this.{self::Class::_#Class#nullableInstanceField};
+ }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::bool _#nonNullableTopLevelField#isSet = false;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int {
+ if(!self::_#nonNullableTopLevelField#isSet) {
+ final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int*} self::nonNullableTopLevelField : ini::computeInitialValue();
+ if(self::_#nonNullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+ self::_#nonNullableTopLevelField = #t15;
+ self::_#nonNullableTopLevelField#isSet = true;
+ }
+ return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
+static get nullableTopLevelField() → core::int? {
+ if(!self::_#nullableTopLevelField#isSet) {
+ final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+ if(self::_#nullableTopLevelField#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+ self::_#nullableTopLevelField = #t19;
+ self::_#nullableTopLevelField#isSet = true;
+ }
+ return self::_#nullableTopLevelField;
+}
+static method main() → void {
+ self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+ self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+ self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+ self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+ self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+ self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+ dynamic value;
+ try {
+ value = f.call();
+ }
+ on core::LateInitializationError catch(final core::LateInitializationError e) {
+ core::print(e);
+ return;
+ }
+ throw "${message}: ${value}";
+}
+
+library;
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int*
+ return null;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart
new file mode 100644
index 0000000..7a87630
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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.
+
+// @dart=2.8
+
+int computeInitialValue() => null;
diff --git a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect
index 266abad..3fc2e39 100644
--- a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect
@@ -23,8 +23,16 @@
this.{self::C::_#C#p1#isSet} = true;
this.{self::C::_#C#p1} = #t2;
}
- get p2() → core::num
- return let final core::num? #t3 = this.{self::C::_#C#p2} in #t3.==(null) ?{core::num} let final core::num #t4 = this.{self::C::pi} in this.{self::C::_#C#p2}.==(null) ?{core::num} this.{self::C::_#C#p2} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.") : #t3{core::num};
+ get p2() → core::num {
+ if(!this.{self::C::_#C#p2#isSet}) {
+ final core::num #t3 = this.{self::C::pi};
+ if(this.{self::C::_#C#p2#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.");
+ this.{self::C::_#C#p2} = #t3;
+ this.{self::C::_#C#p2#isSet} = true;
+ }
+ return let final core::num? #t4 = this.{self::C::_#C#p2} in #t4{core::num};
+ }
}
static method main() → dynamic {
self::expect(3.14, new self::C::•().{self::C::p1});
diff --git a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect
index 266abad..3fc2e39 100644
--- a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect
@@ -23,8 +23,16 @@
this.{self::C::_#C#p1#isSet} = true;
this.{self::C::_#C#p1} = #t2;
}
- get p2() → core::num
- return let final core::num? #t3 = this.{self::C::_#C#p2} in #t3.==(null) ?{core::num} let final core::num #t4 = this.{self::C::pi} in this.{self::C::_#C#p2}.==(null) ?{core::num} this.{self::C::_#C#p2} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.") : #t3{core::num};
+ get p2() → core::num {
+ if(!this.{self::C::_#C#p2#isSet}) {
+ final core::num #t3 = this.{self::C::pi};
+ if(this.{self::C::_#C#p2#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.");
+ this.{self::C::_#C#p2} = #t3;
+ this.{self::C::_#C#p2#isSet} = true;
+ }
+ return let final core::num? #t4 = this.{self::C::_#C#p2} in #t4{core::num};
+ }
}
static method main() → dynamic {
self::expect(3.14, new self::C::•().{self::C::p1});
diff --git a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect
index 671dae2..89e5a3a 100644
--- a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect
@@ -46,8 +46,16 @@
this.{self::A::_#A#finalInstanceField} = #t4;
}
@#C1
- get finalInstanceFieldWithInitializer() → core::int
- return let final core::int? #t5 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t5.==(null) ?{core::int} let final core::int #t6 = 0 in this.{self::A::_#A#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t5{core::int};
+ get finalInstanceFieldWithInitializer() → core::int {
+ if(!this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet}) {
+ final core::int #t5 = 0;
+ if(this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+ this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t5;
+ this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet} = true;
+ }
+ return let final core::int? #t6 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t6{core::int};
+ }
@#C1
get covariantInstanceField() → core::num
return this.{self::A::_#A#covariantInstanceField#isSet} ?{core::num} let final core::num? #t7 = this.{self::A::_#A#covariantInstanceField} in #t7{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -76,8 +84,16 @@
self::A::_#finalStaticField = #t12;
}
@#C1
- static get finalStaticFieldWithInitializer() → core::int
- return let final core::int? #t13 = self::A::_#finalStaticFieldWithInitializer in #t13.==(null) ?{core::int} let final core::int #t14 = 0 in self::A::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::A::_#finalStaticFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t13{core::int};
+ static get finalStaticFieldWithInitializer() → core::int {
+ if(!self::A::_#finalStaticFieldWithInitializer#isSet) {
+ final core::int #t13 = 0;
+ if(self::A::_#finalStaticFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+ self::A::_#finalStaticFieldWithInitializer = #t13;
+ self::A::_#finalStaticFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t14 = self::A::_#finalStaticFieldWithInitializer in #t14{core::int};
+ }
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
field core::int? _#B#instanceField = null;
@@ -114,8 +130,16 @@
this.{self::B::_#B#finalInstanceField} = #t18;
}
@#C1
- get finalInstanceFieldWithInitializer() → core::int
- return let final core::int? #t19 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t19.==(null) ?{core::int} let final core::int #t20 = 0 in this.{self::B::_#B#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t20 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t19{core::int};
+ get finalInstanceFieldWithInitializer() → core::int {
+ if(!this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet}) {
+ final core::int #t19 = 0;
+ if(this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+ this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t19;
+ this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet} = true;
+ }
+ return let final core::int? #t20 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t20{core::int};
+ }
@#C1
get covariantInstanceField() → core::num
return this.{self::B::_#B#covariantInstanceField#isSet} ?{core::num} let final core::num? #t21 = this.{self::B::_#B#covariantInstanceField} in #t21{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -144,8 +168,16 @@
self::B::_#finalStaticField = #t26;
}
@#C1
- static get finalStaticFieldWithInitializer() → core::int
- return let final core::int? #t27 = self::B::_#finalStaticFieldWithInitializer in #t27.==(null) ?{core::int} let final core::int #t28 = 0 in self::B::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::B::_#finalStaticFieldWithInitializer = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t27{core::int};
+ static get finalStaticFieldWithInitializer() → core::int {
+ if(!self::B::_#finalStaticFieldWithInitializer#isSet) {
+ final core::int #t27 = 0;
+ if(self::B::_#finalStaticFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+ self::B::_#finalStaticFieldWithInitializer = #t27;
+ self::B::_#finalStaticFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t28 = self::B::_#finalStaticFieldWithInitializer in #t28{core::int};
+ }
}
extension Extension on self::A {
static field extensionStaticField = self::_#Extension|extensionStaticField;
@@ -192,8 +224,16 @@
self::_#finalTopLevelField = #t32;
}
@#C1
-static get finalTopLevelFieldWithInitializer() → core::int
- return let final core::int? #t33 = self::_#finalTopLevelFieldWithInitializer in #t33.==(null) ?{core::int} let final core::int #t34 = 0 in self::_#finalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#finalTopLevelFieldWithInitializer = #t34 : throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t33{core::int};
+static get finalTopLevelFieldWithInitializer() → core::int {
+ if(!self::_#finalTopLevelFieldWithInitializer#isSet) {
+ final core::int #t33 = 0;
+ if(self::_#finalTopLevelFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.");
+ self::_#finalTopLevelFieldWithInitializer = #t33;
+ self::_#finalTopLevelFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t34 = self::_#finalTopLevelFieldWithInitializer in #t34{core::int};
+}
@#C1
static get Extension|extensionStaticField() → core::int
return self::_#Extension|extensionStaticField#isSet ?{core::int} let final core::int? #t35 = self::_#Extension|extensionStaticField in #t35{core::int} : throw new _in::LateInitializationErrorImpl::•("Field 'extensionStaticField' has not been initialized.");
@@ -214,8 +254,16 @@
self::_#Extension|finalExtensionStaticField = #t38;
}
@#C1
-static get Extension|finalExtensionStaticFieldWithInitializer() → core::int
- return let final core::int? #t39 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t39.==(null) ?{core::int} let final core::int #t40 = 0 in self::_#Extension|finalExtensionStaticFieldWithInitializer.==(null) ?{core::int} self::_#Extension|finalExtensionStaticFieldWithInitializer = #t40 : throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.") : #t39{core::int};
+static get Extension|finalExtensionStaticFieldWithInitializer() → core::int {
+ if(!self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet) {
+ final core::int #t39 = 0;
+ if(self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.");
+ self::_#Extension|finalExtensionStaticFieldWithInitializer = #t39;
+ self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t40 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t40{core::int};
+}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect
index 671dae2..89e5a3a 100644
--- a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect
@@ -46,8 +46,16 @@
this.{self::A::_#A#finalInstanceField} = #t4;
}
@#C1
- get finalInstanceFieldWithInitializer() → core::int
- return let final core::int? #t5 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t5.==(null) ?{core::int} let final core::int #t6 = 0 in this.{self::A::_#A#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t5{core::int};
+ get finalInstanceFieldWithInitializer() → core::int {
+ if(!this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet}) {
+ final core::int #t5 = 0;
+ if(this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+ this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t5;
+ this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet} = true;
+ }
+ return let final core::int? #t6 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t6{core::int};
+ }
@#C1
get covariantInstanceField() → core::num
return this.{self::A::_#A#covariantInstanceField#isSet} ?{core::num} let final core::num? #t7 = this.{self::A::_#A#covariantInstanceField} in #t7{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -76,8 +84,16 @@
self::A::_#finalStaticField = #t12;
}
@#C1
- static get finalStaticFieldWithInitializer() → core::int
- return let final core::int? #t13 = self::A::_#finalStaticFieldWithInitializer in #t13.==(null) ?{core::int} let final core::int #t14 = 0 in self::A::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::A::_#finalStaticFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t13{core::int};
+ static get finalStaticFieldWithInitializer() → core::int {
+ if(!self::A::_#finalStaticFieldWithInitializer#isSet) {
+ final core::int #t13 = 0;
+ if(self::A::_#finalStaticFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+ self::A::_#finalStaticFieldWithInitializer = #t13;
+ self::A::_#finalStaticFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t14 = self::A::_#finalStaticFieldWithInitializer in #t14{core::int};
+ }
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
field core::int? _#B#instanceField = null;
@@ -114,8 +130,16 @@
this.{self::B::_#B#finalInstanceField} = #t18;
}
@#C1
- get finalInstanceFieldWithInitializer() → core::int
- return let final core::int? #t19 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t19.==(null) ?{core::int} let final core::int #t20 = 0 in this.{self::B::_#B#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t20 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t19{core::int};
+ get finalInstanceFieldWithInitializer() → core::int {
+ if(!this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet}) {
+ final core::int #t19 = 0;
+ if(this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+ this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t19;
+ this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet} = true;
+ }
+ return let final core::int? #t20 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t20{core::int};
+ }
@#C1
get covariantInstanceField() → core::num
return this.{self::B::_#B#covariantInstanceField#isSet} ?{core::num} let final core::num? #t21 = this.{self::B::_#B#covariantInstanceField} in #t21{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -144,8 +168,16 @@
self::B::_#finalStaticField = #t26;
}
@#C1
- static get finalStaticFieldWithInitializer() → core::int
- return let final core::int? #t27 = self::B::_#finalStaticFieldWithInitializer in #t27.==(null) ?{core::int} let final core::int #t28 = 0 in self::B::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::B::_#finalStaticFieldWithInitializer = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t27{core::int};
+ static get finalStaticFieldWithInitializer() → core::int {
+ if(!self::B::_#finalStaticFieldWithInitializer#isSet) {
+ final core::int #t27 = 0;
+ if(self::B::_#finalStaticFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+ self::B::_#finalStaticFieldWithInitializer = #t27;
+ self::B::_#finalStaticFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t28 = self::B::_#finalStaticFieldWithInitializer in #t28{core::int};
+ }
}
extension Extension on self::A {
static field extensionStaticField = self::_#Extension|extensionStaticField;
@@ -192,8 +224,16 @@
self::_#finalTopLevelField = #t32;
}
@#C1
-static get finalTopLevelFieldWithInitializer() → core::int
- return let final core::int? #t33 = self::_#finalTopLevelFieldWithInitializer in #t33.==(null) ?{core::int} let final core::int #t34 = 0 in self::_#finalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#finalTopLevelFieldWithInitializer = #t34 : throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t33{core::int};
+static get finalTopLevelFieldWithInitializer() → core::int {
+ if(!self::_#finalTopLevelFieldWithInitializer#isSet) {
+ final core::int #t33 = 0;
+ if(self::_#finalTopLevelFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.");
+ self::_#finalTopLevelFieldWithInitializer = #t33;
+ self::_#finalTopLevelFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t34 = self::_#finalTopLevelFieldWithInitializer in #t34{core::int};
+}
@#C1
static get Extension|extensionStaticField() → core::int
return self::_#Extension|extensionStaticField#isSet ?{core::int} let final core::int? #t35 = self::_#Extension|extensionStaticField in #t35{core::int} : throw new _in::LateInitializationErrorImpl::•("Field 'extensionStaticField' has not been initialized.");
@@ -214,8 +254,16 @@
self::_#Extension|finalExtensionStaticField = #t38;
}
@#C1
-static get Extension|finalExtensionStaticFieldWithInitializer() → core::int
- return let final core::int? #t39 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t39.==(null) ?{core::int} let final core::int #t40 = 0 in self::_#Extension|finalExtensionStaticFieldWithInitializer.==(null) ?{core::int} self::_#Extension|finalExtensionStaticFieldWithInitializer = #t40 : throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.") : #t39{core::int};
+static get Extension|finalExtensionStaticFieldWithInitializer() → core::int {
+ if(!self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet) {
+ final core::int #t39 = 0;
+ if(self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.");
+ self::_#Extension|finalExtensionStaticFieldWithInitializer = #t39;
+ self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet = true;
+ }
+ return let final core::int? #t40 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t40{core::int};
+}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
index 4b5e6e4..af7e11a 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
@@ -15,8 +15,16 @@
constructor •(core::int x) → self::C
: super self::B::•(x)
;
- get y() → core::int
- return let final core::int? #t1 = this.{self::C::_#C#y} in #t1.==(null) ?{core::int} let final core::int #t2 = this.{self::B::x}.{core::num::+}(1) in this.{self::C::_#C#y}.==(null) ?{core::int} this.{self::C::_#C#y} = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.") : #t1{core::int};
+ get y() → core::int {
+ if(!this.{self::C::_#C#y#isSet}) {
+ final core::int #t1 = this.{self::B::x}.{core::num::+}(1);
+ if(this.{self::C::_#C#y#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.");
+ this.{self::C::_#C#y} = #t1;
+ this.{self::C::_#C#y#isSet} = true;
+ }
+ return let final core::int? #t2 = this.{self::C::_#C#y} in #t2{core::int};
+ }
method method() → dynamic
return this.{self::B::x};
}
@@ -40,13 +48,29 @@
static method initLateStaticField1(core::int value) → core::int {
return self::Class::lateStaticField1Init = value;
}
- static get lateStaticField1() → core::int
- return let final core::int? #t3 = self::Class::_#lateStaticField1 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t3{core::int};
+ static get lateStaticField1() → core::int {
+ if(!self::Class::_#lateStaticField1#isSet) {
+ final core::int #t3 = self::Class::initLateStaticField1(87);
+ if(self::Class::_#lateStaticField1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
+ self::Class::_#lateStaticField1 = #t3;
+ self::Class::_#lateStaticField1#isSet = true;
+ }
+ return let final core::int? #t4 = self::Class::_#lateStaticField1 in #t4{core::int};
+ }
static method initLateStaticField2(core::int value) → core::int {
return self::Class::lateStaticField2Init = value;
}
- static get lateStaticField2() → core::int
- return let final core::int? #t5 = self::Class::_#lateStaticField2 in #t5.==(null) ?{core::int} let final core::int #t6 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t5{core::int};
+ static get lateStaticField2() → core::int {
+ if(!self::Class::_#lateStaticField2#isSet) {
+ final core::int #t5 = self::Class::initLateStaticField2(42);
+ if(self::Class::_#lateStaticField2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
+ self::Class::_#lateStaticField2 = #t5;
+ self::Class::_#lateStaticField2#isSet = true;
+ }
+ return let final core::int? #t6 = self::Class::_#lateStaticField2 in #t6{core::int};
+ }
static method staticMethod() → dynamic {
self::expect(null, self::Class::lateStaticField2Init);
self::expect(42, self::Class::lateStaticField2);
@@ -55,8 +79,16 @@
method initLateInstanceField(core::int value) → core::int {
return this.{self::Class::lateInstanceFieldInit} = value;
}
- get lateInstanceField() → core::int
- return let final core::int? #t7 = this.{self::Class::_#Class#lateInstanceField} in #t7.==(null) ?{core::int} let final core::int #t8 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t7{core::int};
+ get lateInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+ final core::int #t7 = this.{self::Class::initLateInstanceField}(16);
+ if(this.{self::Class::_#Class#lateInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#lateInstanceField} = #t7;
+ this.{self::Class::_#Class#lateInstanceField#isSet} = true;
+ }
+ return let final core::int? #t8 = this.{self::Class::_#Class#lateInstanceField} in #t8{core::int};
+ }
method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
return this.{self::Class::lateGenericFieldInit} = value;
}
@@ -104,18 +136,42 @@
static method initLateTopLevelField1(core::int value) → core::int {
return self::lateTopLevelField1Init = value;
}
-static get lateTopLevelField1() → core::int
- return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t11{core::int};
+static get lateTopLevelField1() → core::int {
+ if(!self::_#lateTopLevelField1#isSet) {
+ final core::int #t11 = self::initLateTopLevelField1(123);
+ if(self::_#lateTopLevelField1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
+ self::_#lateTopLevelField1 = #t11;
+ self::_#lateTopLevelField1#isSet = true;
+ }
+ return let final core::int? #t12 = self::_#lateTopLevelField1 in #t12{core::int};
+}
static method Extension|initLateExtensionField1(core::int value) → core::int {
return self::Extension|lateExtensionField1Init = value;
}
-static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t13{core::int};
+static get Extension|lateExtensionField1() → core::int {
+ if(!self::_#Extension|lateExtensionField1#isSet) {
+ final core::int #t13 = self::Extension|initLateExtensionField1(87);
+ if(self::_#Extension|lateExtensionField1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
+ self::_#Extension|lateExtensionField1 = #t13;
+ self::_#Extension|lateExtensionField1#isSet = true;
+ }
+ return let final core::int? #t14 = self::_#Extension|lateExtensionField1 in #t14{core::int};
+}
static method Extension|initLateExtensionField2(core::int value) → core::int {
return self::Extension|lateExtensionField2Init = value;
}
-static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} let final core::int #t16 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t15{core::int};
+static get Extension|lateExtensionField2() → core::int {
+ if(!self::_#Extension|lateExtensionField2#isSet) {
+ final core::int #t15 = self::Extension|initLateExtensionField2(42);
+ if(self::_#Extension|lateExtensionField2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
+ self::_#Extension|lateExtensionField2 = #t15;
+ self::_#Extension|lateExtensionField2#isSet = true;
+ }
+ return let final core::int? #t16 = self::_#Extension|lateExtensionField2 in #t16{core::int};
+}
static method Extension|staticMethod() → dynamic {
self::expect(null, self::Extension|lateExtensionField2Init);
self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
index 4b5e6e4..af7e11a 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
@@ -15,8 +15,16 @@
constructor •(core::int x) → self::C
: super self::B::•(x)
;
- get y() → core::int
- return let final core::int? #t1 = this.{self::C::_#C#y} in #t1.==(null) ?{core::int} let final core::int #t2 = this.{self::B::x}.{core::num::+}(1) in this.{self::C::_#C#y}.==(null) ?{core::int} this.{self::C::_#C#y} = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.") : #t1{core::int};
+ get y() → core::int {
+ if(!this.{self::C::_#C#y#isSet}) {
+ final core::int #t1 = this.{self::B::x}.{core::num::+}(1);
+ if(this.{self::C::_#C#y#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.");
+ this.{self::C::_#C#y} = #t1;
+ this.{self::C::_#C#y#isSet} = true;
+ }
+ return let final core::int? #t2 = this.{self::C::_#C#y} in #t2{core::int};
+ }
method method() → dynamic
return this.{self::B::x};
}
@@ -40,13 +48,29 @@
static method initLateStaticField1(core::int value) → core::int {
return self::Class::lateStaticField1Init = value;
}
- static get lateStaticField1() → core::int
- return let final core::int? #t3 = self::Class::_#lateStaticField1 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t3{core::int};
+ static get lateStaticField1() → core::int {
+ if(!self::Class::_#lateStaticField1#isSet) {
+ final core::int #t3 = self::Class::initLateStaticField1(87);
+ if(self::Class::_#lateStaticField1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
+ self::Class::_#lateStaticField1 = #t3;
+ self::Class::_#lateStaticField1#isSet = true;
+ }
+ return let final core::int? #t4 = self::Class::_#lateStaticField1 in #t4{core::int};
+ }
static method initLateStaticField2(core::int value) → core::int {
return self::Class::lateStaticField2Init = value;
}
- static get lateStaticField2() → core::int
- return let final core::int? #t5 = self::Class::_#lateStaticField2 in #t5.==(null) ?{core::int} let final core::int #t6 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t5{core::int};
+ static get lateStaticField2() → core::int {
+ if(!self::Class::_#lateStaticField2#isSet) {
+ final core::int #t5 = self::Class::initLateStaticField2(42);
+ if(self::Class::_#lateStaticField2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
+ self::Class::_#lateStaticField2 = #t5;
+ self::Class::_#lateStaticField2#isSet = true;
+ }
+ return let final core::int? #t6 = self::Class::_#lateStaticField2 in #t6{core::int};
+ }
static method staticMethod() → dynamic {
self::expect(null, self::Class::lateStaticField2Init);
self::expect(42, self::Class::lateStaticField2);
@@ -55,8 +79,16 @@
method initLateInstanceField(core::int value) → core::int {
return this.{self::Class::lateInstanceFieldInit} = value;
}
- get lateInstanceField() → core::int
- return let final core::int? #t7 = this.{self::Class::_#Class#lateInstanceField} in #t7.==(null) ?{core::int} let final core::int #t8 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t7{core::int};
+ get lateInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+ final core::int #t7 = this.{self::Class::initLateInstanceField}(16);
+ if(this.{self::Class::_#Class#lateInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
+ this.{self::Class::_#Class#lateInstanceField} = #t7;
+ this.{self::Class::_#Class#lateInstanceField#isSet} = true;
+ }
+ return let final core::int? #t8 = this.{self::Class::_#Class#lateInstanceField} in #t8{core::int};
+ }
method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
return this.{self::Class::lateGenericFieldInit} = value;
}
@@ -104,18 +136,42 @@
static method initLateTopLevelField1(core::int value) → core::int {
return self::lateTopLevelField1Init = value;
}
-static get lateTopLevelField1() → core::int
- return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t11{core::int};
+static get lateTopLevelField1() → core::int {
+ if(!self::_#lateTopLevelField1#isSet) {
+ final core::int #t11 = self::initLateTopLevelField1(123);
+ if(self::_#lateTopLevelField1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
+ self::_#lateTopLevelField1 = #t11;
+ self::_#lateTopLevelField1#isSet = true;
+ }
+ return let final core::int? #t12 = self::_#lateTopLevelField1 in #t12{core::int};
+}
static method Extension|initLateExtensionField1(core::int value) → core::int {
return self::Extension|lateExtensionField1Init = value;
}
-static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t13{core::int};
+static get Extension|lateExtensionField1() → core::int {
+ if(!self::_#Extension|lateExtensionField1#isSet) {
+ final core::int #t13 = self::Extension|initLateExtensionField1(87);
+ if(self::_#Extension|lateExtensionField1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
+ self::_#Extension|lateExtensionField1 = #t13;
+ self::_#Extension|lateExtensionField1#isSet = true;
+ }
+ return let final core::int? #t14 = self::_#Extension|lateExtensionField1 in #t14{core::int};
+}
static method Extension|initLateExtensionField2(core::int value) → core::int {
return self::Extension|lateExtensionField2Init = value;
}
-static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} let final core::int #t16 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t15{core::int};
+static get Extension|lateExtensionField2() → core::int {
+ if(!self::_#Extension|lateExtensionField2#isSet) {
+ final core::int #t15 = self::Extension|initLateExtensionField2(42);
+ if(self::_#Extension|lateExtensionField2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
+ self::_#Extension|lateExtensionField2 = #t15;
+ self::_#Extension|lateExtensionField2#isSet = true;
+ }
+ return let final core::int? #t16 = self::_#Extension|lateExtensionField2 in #t16{core::int};
+}
static method Extension|staticMethod() → dynamic {
self::expect(null, self::Extension|lateExtensionField2Init);
self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.weak.expect b/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
index 78fc27d..3a9b187 100644
--- a/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
@@ -93,8 +93,16 @@
const constructor •() → self::B
: super core::Object::•()
;
- get x() → core::int
- return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+ get x() → core::int {
+ if(!this.{self::B::_#B#x#isSet}) {
+ final core::int #t3 = 42;
+ if(this.{self::B::_#B#x#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+ this.{self::B::_#B#x} = #t3;
+ this.{self::B::_#B#x#isSet} = true;
+ }
+ return let final core::int? #t4 = this.{self::B::_#B#x} in #t4{core::int};
+ }
}
class C extends core::Object {
field core::int? _#C#x = null;
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
index 92573ba..27b946d 100644
--- a/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
@@ -93,8 +93,16 @@
const constructor •() → self::B
: super core::Object::•()
;
- get x() → core::int
- return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+ get x() → core::int {
+ if(!this.{self::B::_#B#x#isSet}) {
+ final core::int #t3 = 42;
+ if(this.{self::B::_#B#x#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+ this.{self::B::_#B#x} = #t3;
+ this.{self::B::_#B#x#isSet} = true;
+ }
+ return let final core::int? #t4 = this.{self::B::_#B#x} in #t4{core::int};
+ }
}
class C extends core::Object {
field core::int? _#C#x = null;
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.weak.expect b/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
index a4add12..961d813 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
@@ -84,8 +84,16 @@
this.{self::SubClass::_#SubClass#field3#isSet} = true;
this.{self::SubClass::_#SubClass#field3} = #t14;
}
- get field4() → core::int
- return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
+ get field4() → core::int {
+ if(!this.{self::SubClass::_#SubClass#field4#isSet}) {
+ final core::int #t15 = 0;
+ if(this.{self::SubClass::_#SubClass#field4#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.");
+ this.{self::SubClass::_#SubClass#field4} = #t15;
+ this.{self::SubClass::_#SubClass#field4#isSet} = true;
+ }
+ return let final core::int? #t16 = this.{self::SubClass::_#SubClass#field4} in #t16{core::int};
+ }
get directField1() → core::int
return super.{self::Class::field1};
set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
index a4add12..961d813 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
@@ -84,8 +84,16 @@
this.{self::SubClass::_#SubClass#field3#isSet} = true;
this.{self::SubClass::_#SubClass#field3} = #t14;
}
- get field4() → core::int
- return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
+ get field4() → core::int {
+ if(!this.{self::SubClass::_#SubClass#field4#isSet}) {
+ final core::int #t15 = 0;
+ if(this.{self::SubClass::_#SubClass#field4#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.");
+ this.{self::SubClass::_#SubClass#field4} = #t15;
+ this.{self::SubClass::_#SubClass#field4#isSet} = true;
+ }
+ return let final core::int? #t16 = this.{self::SubClass::_#SubClass#field4} in #t16{core::int};
+ }
get directField1() → core::int
return super.{self::Class::field1};
set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect
index 2c3785b..e51321c 100644
--- a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect
@@ -47,8 +47,16 @@
synthetic constructor •() → self::C
: super self::A::•()
;
- get x() → core::int
- return let final core::int? #t4 = this.{self::C::_#C#x} in #t4.==(null) ?{core::int} let final core::int #t5 = 2 in this.{self::C::_#C#x}.==(null) ?{core::int} this.{self::C::_#C#x} = #t5 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t4{core::int};
+ get x() → core::int {
+ if(!this.{self::C::_#C#x#isSet}) {
+ final core::int #t4 = 2;
+ if(this.{self::C::_#C#x#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+ this.{self::C::_#C#x} = #t4;
+ this.{self::C::_#C#x#isSet} = true;
+ }
+ return let final core::int? #t5 = this.{self::C::_#C#x} in #t5{core::int};
+ }
get y() → core::int? {
if(!this.{self::C::_#C#y#isSet}) {
final core::int? #t6 = 2;
diff --git a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect
index 2c3785b..e51321c 100644
--- a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect
@@ -47,8 +47,16 @@
synthetic constructor •() → self::C
: super self::A::•()
;
- get x() → core::int
- return let final core::int? #t4 = this.{self::C::_#C#x} in #t4.==(null) ?{core::int} let final core::int #t5 = 2 in this.{self::C::_#C#x}.==(null) ?{core::int} this.{self::C::_#C#x} = #t5 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t4{core::int};
+ get x() → core::int {
+ if(!this.{self::C::_#C#x#isSet}) {
+ final core::int #t4 = 2;
+ if(this.{self::C::_#C#x#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+ this.{self::C::_#C#x} = #t4;
+ this.{self::C::_#C#x#isSet} = true;
+ }
+ return let final core::int? #t5 = this.{self::C::_#C#x} in #t5{core::int};
+ }
get y() → core::int? {
if(!this.{self::C::_#C#y#isSet}) {
final core::int? #t6 = 2;
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/folder.options b/pkg/front_end/testcases/late_lowering_sentinel/folder.options
new file mode 100644
index 0000000..8d48ec9
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/folder.options
@@ -0,0 +1,3 @@
+--enable-experiment=non-nullable
+--force-late-lowering
+--force-late-lowering-sentinel
\ No newline at end of file
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart
new file mode 100644
index 0000000..3434c11
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, 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.
+
+late int? nullableTopLevelField;
+late int nonNullableTopLevelField;
+late int? nullableTopLevelFieldWithInitializer = null;
+late int nonNullableTopLevelFieldWithInitializer = 0;
+late final int? nullableFinalTopLevelField;
+late final int nonNullableFinalTopLevelField;
+late final int? nullableFinalTopLevelFieldWithInitializer = null;
+late final int nonNullableFinalTopLevelFieldWithInitializer = 0;
+
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.outline.expect
new file mode 100644
index 0000000..98525c7
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.outline.expect
@@ -0,0 +1,28 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field core::int? _#nullableTopLevelField;
+static field core::int? _#nonNullableTopLevelField;
+static field core::int? _#nullableTopLevelFieldWithInitializer;
+static field core::int? _#nonNullableTopLevelFieldWithInitializer;
+static field core::int? _#nullableFinalTopLevelField;
+static field core::int? _#nonNullableFinalTopLevelField;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer;
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer;
+static get nullableTopLevelField() → core::int?;
+static set nullableTopLevelField(core::int? #t1) → void;
+static get nonNullableTopLevelField() → core::int;
+static set nonNullableTopLevelField(core::int #t2) → void;
+static get nullableTopLevelFieldWithInitializer() → core::int?;
+static set nullableTopLevelFieldWithInitializer(core::int? #t3) → void;
+static get nonNullableTopLevelFieldWithInitializer() → core::int;
+static set nonNullableTopLevelFieldWithInitializer(core::int #t4) → void;
+static get nullableFinalTopLevelField() → core::int?;
+static set nullableFinalTopLevelField(core::int? #t5) → void;
+static get nonNullableFinalTopLevelField() → core::int;
+static set nonNullableFinalTopLevelField(core::int #t6) → void;
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+ return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+ self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+ return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+ self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+ self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+ self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+ return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+ if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+ self::_#nullableFinalTopLevelField = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+ return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+ if(self::_#nonNullableFinalTopLevelField.==(null))
+ self::_#nonNullableFinalTopLevelField = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.transformed.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.transformed.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+ return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+ self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+ return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+ self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+ self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+ self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+ return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+ if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+ self::_#nullableFinalTopLevelField = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+ return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+ if(self::_#nonNullableFinalTopLevelField.==(null))
+ self::_#nonNullableFinalTopLevelField = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.textual_outline.expect
new file mode 100644
index 0000000..34e9a83
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.textual_outline.expect
@@ -0,0 +1,19 @@
+late int;
+?
+nullableTopLevelField;
+late int ;
+nonNullableTopLevelField;
+late int;
+?
+nullableTopLevelFieldWithInitializer = null;
+late int ;
+nonNullableTopLevelFieldWithInitializer = 0;
+late ;
+final int? nullableFinalTopLevelField;
+late ;
+final int nonNullableFinalTopLevelField;
+late ;
+final int? nullableFinalTopLevelFieldWithInitializer = null;
+late ;
+final int nonNullableFinalTopLevelFieldWithInitializer = 0;
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+ return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+ self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+ return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+ self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+ self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+ self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+ return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+ if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+ self::_#nullableFinalTopLevelField = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+ return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+ if(self::_#nonNullableFinalTopLevelField.==(null))
+ self::_#nonNullableFinalTopLevelField = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.transformed.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.transformed.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+ return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+ self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+ return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+ self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+ self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+ self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+ return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+ if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+ self::_#nullableFinalTopLevelField = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+ return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+ if(self::_#nonNullableFinalTopLevelField.==(null))
+ self::_#nonNullableFinalTopLevelField = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+ return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+ return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart
new file mode 100644
index 0000000..b0799a6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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.
+
+test() {
+ late int? nullableTopLevelLocal;
+ late int nonNullableTopLevelLocal;
+ late int? nullableTopLevelLocalWithInitializer = null;
+ late int nonNullableTopLevelLocalWithInitializer = 0;
+ late final int? nullableFinalTopLevelLocal;
+ late final int nonNullableFinalTopLevelLocal;
+ late final int? nullableFinalTopLevelLocalWithInitializer = null;
+ late final int nonNullableFinalTopLevelLocalWithInitializer = 0;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.outline.expect
new file mode 100644
index 0000000..64923de
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.outline.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method test() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+ core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocal#get() → core::int?
+ return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+ function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+ return nullableTopLevelLocal = #t2;
+ core::int? nonNullableTopLevelLocal;
+ function #nonNullableTopLevelLocal#get() → core::int
+ return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+ function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+ return nonNullableTopLevelLocal = #t4;
+ core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+ function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+ return nullableTopLevelLocalWithInitializer = #t6;
+ core::int? nonNullableTopLevelLocalWithInitializer;
+ function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+ function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+ return nonNullableTopLevelLocalWithInitializer = #t8;
+ final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocal#get() → core::int?
+ return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+ function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+ if(_in::isSentinel(nullableFinalTopLevelLocal))
+ return nullableFinalTopLevelLocal = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nonNullableFinalTopLevelLocal;
+ function #nonNullableFinalTopLevelLocal#get() → core::int
+ return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+ function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+ if(nonNullableFinalTopLevelLocal.==(null))
+ return nonNullableFinalTopLevelLocal = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+ final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+ function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.transformed.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.transformed.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+ core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocal#get() → core::int?
+ return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+ function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+ return nullableTopLevelLocal = #t2;
+ core::int? nonNullableTopLevelLocal;
+ function #nonNullableTopLevelLocal#get() → core::int
+ return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+ function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+ return nonNullableTopLevelLocal = #t4;
+ core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+ function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+ return nullableTopLevelLocalWithInitializer = #t6;
+ core::int? nonNullableTopLevelLocalWithInitializer;
+ function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+ function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+ return nonNullableTopLevelLocalWithInitializer = #t8;
+ final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocal#get() → core::int?
+ return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+ function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+ if(_in::isSentinel(nullableFinalTopLevelLocal))
+ return nullableFinalTopLevelLocal = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nonNullableFinalTopLevelLocal;
+ function #nonNullableFinalTopLevelLocal#get() → core::int
+ return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+ function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+ if(nonNullableFinalTopLevelLocal.==(null))
+ return nonNullableFinalTopLevelLocal = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+ final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+ function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline.expect
new file mode 100644
index 0000000..ec6b9e0
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f67dbb0
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+main() {}
+test() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+ core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocal#get() → core::int?
+ return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+ function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+ return nullableTopLevelLocal = #t2;
+ core::int? nonNullableTopLevelLocal;
+ function #nonNullableTopLevelLocal#get() → core::int
+ return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+ function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+ return nonNullableTopLevelLocal = #t4;
+ core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+ function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+ return nullableTopLevelLocalWithInitializer = #t6;
+ core::int? nonNullableTopLevelLocalWithInitializer;
+ function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+ function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+ return nonNullableTopLevelLocalWithInitializer = #t8;
+ final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocal#get() → core::int?
+ return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+ function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+ if(_in::isSentinel(nullableFinalTopLevelLocal))
+ return nullableFinalTopLevelLocal = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nonNullableFinalTopLevelLocal;
+ function #nonNullableFinalTopLevelLocal#get() → core::int
+ return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+ function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+ if(nonNullableFinalTopLevelLocal.==(null))
+ return nonNullableFinalTopLevelLocal = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+ final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+ function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.transformed.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.transformed.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+ core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocal#get() → core::int?
+ return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+ function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+ return nullableTopLevelLocal = #t2;
+ core::int? nonNullableTopLevelLocal;
+ function #nonNullableTopLevelLocal#get() → core::int
+ return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+ function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+ return nonNullableTopLevelLocal = #t4;
+ core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+ function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+ return nullableTopLevelLocalWithInitializer = #t6;
+ core::int? nonNullableTopLevelLocalWithInitializer;
+ function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+ function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+ return nonNullableTopLevelLocalWithInitializer = #t8;
+ final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocal#get() → core::int?
+ return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+ function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+ if(_in::isSentinel(nullableFinalTopLevelLocal))
+ return nullableFinalTopLevelLocal = #t10;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nonNullableFinalTopLevelLocal;
+ function #nonNullableFinalTopLevelLocal#get() → core::int
+ return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+ function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+ if(nonNullableFinalTopLevelLocal.==(null))
+ return nonNullableFinalTopLevelLocal = #t12;
+ else
+ throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+ final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+ function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+ return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+ final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+ function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+ return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect
index 4ac62a9..6bc5231 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect
@@ -188,27 +188,27 @@
constructor •(core::int initializedField1) → self::A
;
abstract get fieldWithInitializer() → core::int;
- abstract set fieldWithInitializer(core::int #t1) → void;
+ abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
abstract get initializedField1() → core::int;
- abstract set initializedField1(core::int #t2) → void;
+ abstract set initializedField1(core::int #externalFieldValue) → void;
abstract get initializedField2() → core::int;
- abstract set initializedField2(core::int #t3) → void;
+ abstract set initializedField2(core::int #externalFieldValue) → void;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t4) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t5) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
external get externalLateInstanceField() → core::int;
- external set externalLateInstanceField(core::int #t6) → void;
+ external set externalLateInstanceField(core::int #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
static field core::int staticField;
static final field core::int finalStaticField;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t7) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t8) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -223,7 +223,7 @@
static field core::int Extension|extensionStaticField;
static final field core::int Extension|finalExtensionStaticField;
static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t9) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
static abstract get Extension|finalExtensionInstanceField() → core::int;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect
@@ -220,27 +220,27 @@
^^^^^^^^^^^^^^^^^"
;
abstract get fieldWithInitializer() → core::int;
- abstract set fieldWithInitializer(core::int #t3) → void;
+ abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
abstract get initializedField1() → core::int;
- abstract set initializedField1(core::int #t4) → void;
+ abstract set initializedField1(core::int #externalFieldValue) → void;
abstract get initializedField2() → core::int;
- abstract set initializedField2(core::int #t5) → void;
+ abstract set initializedField2(core::int #externalFieldValue) → void;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t6) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t7) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
external get externalLateInstanceField() → core::int;
- external set externalLateInstanceField(core::int #t8) → void;
+ external set externalLateInstanceField(core::int #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
static field core::int staticField = null;
static final field core::int finalStaticField = null;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t9) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t10) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
static field core::int Extension|extensionStaticField;
static final field core::int Extension|finalExtensionStaticField;
static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
static abstract get Extension|finalExtensionInstanceField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect
@@ -220,27 +220,27 @@
^^^^^^^^^^^^^^^^^"
;
abstract get fieldWithInitializer() → core::int;
- abstract set fieldWithInitializer(core::int #t3) → void;
+ abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
abstract get initializedField1() → core::int;
- abstract set initializedField1(core::int #t4) → void;
+ abstract set initializedField1(core::int #externalFieldValue) → void;
abstract get initializedField2() → core::int;
- abstract set initializedField2(core::int #t5) → void;
+ abstract set initializedField2(core::int #externalFieldValue) → void;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t6) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t7) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
external get externalLateInstanceField() → core::int;
- external set externalLateInstanceField(core::int #t8) → void;
+ external set externalLateInstanceField(core::int #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
static field core::int staticField = null;
static final field core::int finalStaticField = null;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t9) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t10) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
static field core::int Extension|extensionStaticField;
static final field core::int Extension|finalExtensionStaticField;
static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
static abstract get Extension|finalExtensionInstanceField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect
@@ -220,27 +220,27 @@
^^^^^^^^^^^^^^^^^"
;
abstract get fieldWithInitializer() → core::int;
- abstract set fieldWithInitializer(core::int #t3) → void;
+ abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
abstract get initializedField1() → core::int;
- abstract set initializedField1(core::int #t4) → void;
+ abstract set initializedField1(core::int #externalFieldValue) → void;
abstract get initializedField2() → core::int;
- abstract set initializedField2(core::int #t5) → void;
+ abstract set initializedField2(core::int #externalFieldValue) → void;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t6) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t7) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
external get externalLateInstanceField() → core::int;
- external set externalLateInstanceField(core::int #t8) → void;
+ external set externalLateInstanceField(core::int #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
static field core::int staticField = null;
static final field core::int finalStaticField = null;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t9) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t10) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
static field core::int Extension|extensionStaticField;
static final field core::int Extension|finalExtensionStaticField;
static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
static abstract get Extension|finalExtensionInstanceField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect
@@ -220,27 +220,27 @@
^^^^^^^^^^^^^^^^^"
;
abstract get fieldWithInitializer() → core::int;
- abstract set fieldWithInitializer(core::int #t3) → void;
+ abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
abstract get initializedField1() → core::int;
- abstract set initializedField1(core::int #t4) → void;
+ abstract set initializedField1(core::int #externalFieldValue) → void;
abstract get initializedField2() → core::int;
- abstract set initializedField2(core::int #t5) → void;
+ abstract set initializedField2(core::int #externalFieldValue) → void;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t6) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t7) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
external get externalLateInstanceField() → core::int;
- external set externalLateInstanceField(core::int #t8) → void;
+ external set externalLateInstanceField(core::int #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
static field core::int staticField = null;
static final field core::int finalStaticField = null;
external get externalInstanceField() → core::int;
- external set externalInstanceField(core::int #t9) → void;
+ external set externalInstanceField(core::int #externalFieldValue) → void;
external get externalFinalInstanceField() → core::int;
external get externalCovariantInstanceField() → core::num;
- external set externalCovariantInstanceField(covariant core::num #t10) → void;
+ external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
static field core::int Extension|extensionStaticField;
static final field core::int Extension|finalExtensionStaticField;
static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
static abstract get Extension|finalExtensionInstanceField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect
index e13a36a..ff6c1e2 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect
@@ -6,17 +6,17 @@
synthetic constructor •() → self::A
;
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t1) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t2) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t3) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t4) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t1) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t2) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t3) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t4) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t1) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t2) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t3) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t4) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t1) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t2) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t3) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t4) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t1) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t2) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
abstract get instanceField() → core::int;
- abstract set instanceField(core::int #t3) → void;
+ abstract set instanceField(core::int #externalFieldValue) → void;
abstract get finalInstanceField() → core::int;
abstract get covariantInstanceField() → core::num;
- abstract set covariantInstanceField(covariant core::num #t4) → void;
+ abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect
index 492b9a7..21e1617 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect
@@ -6,17 +6,17 @@
synthetic constructor •() → self::A
;
abstract get i1() → core::int;
- abstract set i1(core::int #t1) → void;
+ abstract set i1(core::int #externalFieldValue) → void;
abstract get i2() → core::int;
- abstract set i2(core::int #t2) → void;
+ abstract set i2(core::int #externalFieldValue) → void;
abstract get x() → dynamic;
- abstract set x(dynamic #t3) → void;
+ abstract set x(dynamic #externalFieldValue) → void;
abstract get fi() → core::int;
abstract get fx() → dynamic;
abstract get cn() → core::num;
- abstract set cn(covariant core::num #t4) → void;
+ abstract set cn(covariant core::num #externalFieldValue) → void;
abstract get cx() → dynamic;
- abstract set cx(covariant dynamic #t5) → void;
+ abstract set cx(covariant dynamic #externalFieldValue) → void;
}
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get i1() → core::int;
- abstract set i1(core::int #t1) → void;
+ abstract set i1(core::int #externalFieldValue) → void;
abstract get i2() → core::int;
- abstract set i2(core::int #t2) → void;
+ abstract set i2(core::int #externalFieldValue) → void;
abstract get x() → dynamic;
- abstract set x(dynamic #t3) → void;
+ abstract set x(dynamic #externalFieldValue) → void;
abstract get fi() → core::int;
abstract get fx() → dynamic;
abstract get cn() → core::num;
- abstract set cn(covariant core::num #t4) → void;
+ abstract set cn(covariant core::num #externalFieldValue) → void;
abstract get cx() → dynamic;
- abstract set cx(covariant dynamic #t5) → void;
+ abstract set cx(covariant dynamic #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get i1() → core::int;
- abstract set i1(core::int #t1) → void;
+ abstract set i1(core::int #externalFieldValue) → void;
abstract get i2() → core::int;
- abstract set i2(core::int #t2) → void;
+ abstract set i2(core::int #externalFieldValue) → void;
abstract get x() → dynamic;
- abstract set x(dynamic #t3) → void;
+ abstract set x(dynamic #externalFieldValue) → void;
abstract get fi() → core::int;
abstract get fx() → dynamic;
abstract get cn() → core::num;
- abstract set cn(covariant core::num #t4) → void;
+ abstract set cn(covariant core::num #externalFieldValue) → void;
abstract get cx() → dynamic;
- abstract set cx(covariant dynamic #t5) → void;
+ abstract set cx(covariant dynamic #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get i1() → core::int;
- abstract set i1(core::int #t1) → void;
+ abstract set i1(core::int #externalFieldValue) → void;
abstract get i2() → core::int;
- abstract set i2(core::int #t2) → void;
+ abstract set i2(core::int #externalFieldValue) → void;
abstract get x() → dynamic;
- abstract set x(dynamic #t3) → void;
+ abstract set x(dynamic #externalFieldValue) → void;
abstract get fi() → core::int;
abstract get fx() → dynamic;
abstract get cn() → core::num;
- abstract set cn(covariant core::num #t4) → void;
+ abstract set cn(covariant core::num #externalFieldValue) → void;
abstract get cx() → dynamic;
- abstract set cx(covariant dynamic #t5) → void;
+ abstract set cx(covariant dynamic #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
abstract get i1() → core::int;
- abstract set i1(core::int #t1) → void;
+ abstract set i1(core::int #externalFieldValue) → void;
abstract get i2() → core::int;
- abstract set i2(core::int #t2) → void;
+ abstract set i2(core::int #externalFieldValue) → void;
abstract get x() → dynamic;
- abstract set x(dynamic #t3) → void;
+ abstract set x(dynamic #externalFieldValue) → void;
abstract get fi() → core::int;
abstract get fx() → dynamic;
abstract get cn() → core::num;
- abstract set cn(covariant core::num #t4) → void;
+ abstract set cn(covariant core::num #externalFieldValue) → void;
abstract get cx() → dynamic;
- abstract set cx(covariant dynamic #t5) → void;
+ abstract set cx(covariant dynamic #externalFieldValue) → void;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect
index 197f942..d92b2fe 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect
@@ -6,18 +6,18 @@
constructor •(core::int initializedField1) → self::A
;
external get fieldWithInitializer() → core::int;
- external set fieldWithInitializer(core::int #t1) → void;
+ external set fieldWithInitializer(core::int #externalFieldValue) → void;
external get initializedField1() → core::int;
- external set initializedField1(core::int #t2) → void;
+ external set initializedField1(core::int #externalFieldValue) → void;
external get initializedField2() → core::int;
- external set initializedField2(core::int #t3) → void;
+ external set initializedField2(core::int #externalFieldValue) → void;
external static get staticField() → core::int;
- external static set staticField(core::int #t4) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
external static get staticField() → core::int;
- external static set staticField(core::int #t5) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
extension Extension on self::A {
@@ -29,15 +29,15 @@
static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
}
external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t6) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
external static get finalTopLevelField() → core::int;
external static get constField() → core::int;
-external static set constField(core::int #t7) → void;
+external static set constField(core::int #externalFieldValue) → void;
external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t8) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionInstanceField() → core::int;
external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t9) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionStaticField() → core::int;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect
@@ -86,18 +86,18 @@
^^^^^^^^^^^^^^^^^"
;
external get fieldWithInitializer() → core::int;
- external set fieldWithInitializer(core::int #t3) → void;
+ external set fieldWithInitializer(core::int #externalFieldValue) → void;
external get initializedField1() → core::int;
- external set initializedField1(core::int #t4) → void;
+ external set initializedField1(core::int #externalFieldValue) → void;
external get initializedField2() → core::int;
- external set initializedField2(core::int #t5) → void;
+ external set initializedField2(core::int #externalFieldValue) → void;
external static get staticField() → core::int;
- external static set staticField(core::int #t6) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
external static get staticField() → core::int;
- external static set staticField(core::int #t7) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
extension Extension on self::A {
@@ -109,14 +109,14 @@
static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
}
external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
external static get finalTopLevelField() → core::int;
external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionInstanceField() → core::int;
external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionStaticField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect
@@ -86,18 +86,18 @@
^^^^^^^^^^^^^^^^^"
;
external get fieldWithInitializer() → core::int;
- external set fieldWithInitializer(core::int #t3) → void;
+ external set fieldWithInitializer(core::int #externalFieldValue) → void;
external get initializedField1() → core::int;
- external set initializedField1(core::int #t4) → void;
+ external set initializedField1(core::int #externalFieldValue) → void;
external get initializedField2() → core::int;
- external set initializedField2(core::int #t5) → void;
+ external set initializedField2(core::int #externalFieldValue) → void;
external static get staticField() → core::int;
- external static set staticField(core::int #t6) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
external static get staticField() → core::int;
- external static set staticField(core::int #t7) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
extension Extension on self::A {
@@ -109,14 +109,14 @@
static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
}
external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
external static get finalTopLevelField() → core::int;
external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionInstanceField() → core::int;
external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionStaticField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect
@@ -86,18 +86,18 @@
^^^^^^^^^^^^^^^^^"
;
external get fieldWithInitializer() → core::int;
- external set fieldWithInitializer(core::int #t3) → void;
+ external set fieldWithInitializer(core::int #externalFieldValue) → void;
external get initializedField1() → core::int;
- external set initializedField1(core::int #t4) → void;
+ external set initializedField1(core::int #externalFieldValue) → void;
external get initializedField2() → core::int;
- external set initializedField2(core::int #t5) → void;
+ external set initializedField2(core::int #externalFieldValue) → void;
external static get staticField() → core::int;
- external static set staticField(core::int #t6) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
external static get staticField() → core::int;
- external static set staticField(core::int #t7) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
extension Extension on self::A {
@@ -109,14 +109,14 @@
static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
}
external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
external static get finalTopLevelField() → core::int;
external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionInstanceField() → core::int;
external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionStaticField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect
@@ -86,18 +86,18 @@
^^^^^^^^^^^^^^^^^"
;
external get fieldWithInitializer() → core::int;
- external set fieldWithInitializer(core::int #t3) → void;
+ external set fieldWithInitializer(core::int #externalFieldValue) → void;
external get initializedField1() → core::int;
- external set initializedField1(core::int #t4) → void;
+ external set initializedField1(core::int #externalFieldValue) → void;
external get initializedField2() → core::int;
- external set initializedField2(core::int #t5) → void;
+ external set initializedField2(core::int #externalFieldValue) → void;
external static get staticField() → core::int;
- external static set staticField(core::int #t6) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
external static get staticField() → core::int;
- external static set staticField(core::int #t7) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
external static get finalStaticField() → core::int;
}
extension Extension on self::A {
@@ -109,14 +109,14 @@
static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
}
external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
external static get finalTopLevelField() → core::int;
external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionInstanceField() → core::int;
external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
external static get Extension|finalExtensionStaticField() → core::int;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect
index b475be4..3a6dda73 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect
@@ -13,67 +13,67 @@
@self::Annotation::•()
external get instanceField() → core::int;
@self::Annotation::•()
- external set instanceField(core::int #t1) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external get finalInstanceField() → core::int;
@self::Annotation::•()
external get covariantInstanceField() → core::num;
@self::Annotation::•()
- external set covariantInstanceField(covariant core::num #t2) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@self::Annotation::•()
external static get staticField() → core::int;
@self::Annotation::•()
- external static set staticField(core::int #t3) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t4) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t6) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
@self::Annotation::•()
external get instanceField() → core::int;
@self::Annotation::•()
- external set instanceField(core::int #t7) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external get finalInstanceField() → core::int;
@self::Annotation::•()
external get covariantInstanceField() → core::num;
@self::Annotation::•()
- external set covariantInstanceField(covariant core::num #t8) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@self::Annotation::•()
external static get staticField() → core::int;
@self::Annotation::•()
- external static set staticField(core::int #t9) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t10) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t12) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
class C extends core::Object implements self::A {
synthetic constructor •() → self::C
;
external get instanceField() → core::int;
- external set instanceField(core::int #t13) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
external get finalInstanceField() → core::int;
external get covariantInstanceField() → core::num;
- external set covariantInstanceField(covariant core::num #t14) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t15) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -92,29 +92,29 @@
@self::Annotation::•()
external static get topLevelField() → core::int;
@self::Annotation::•()
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external static get finalTopLevelField() → core::int;
external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
external static get untypedFinalTopLevelField() → dynamic;
@self::Annotation::•()
external static get Extension|extensionInstanceField() → core::int;
@self::Annotation::•()
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external static get Extension|finalExtensionInstanceField() → core::int;
@self::Annotation::•()
external static get Extension|extensionStaticField() → core::int;
@self::Annotation::•()
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
@self::Annotation::•()
external static get Extension|finalExtensionStaticField() → core::int;
external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionStaticField() → dynamic;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect
@@ -14,52 +14,52 @@
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t1) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t2) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t3) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t4) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t6) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t7) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t8) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t9) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t10) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t12) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
: super core::Object::•()
;
external get instanceField() → core::int;
- external set instanceField(core::int #t13) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
external get finalInstanceField() → core::int;
external get covariantInstanceField() → core::num;
- external set covariantInstanceField(covariant core::num #t14) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t15) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
@#C1
external static get topLevelField() → core::int;
@#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
@#C1
external static get finalTopLevelField() → core::int;
external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
external static get untypedFinalTopLevelField() → dynamic;
@#C1
external static get Extension|extensionInstanceField() → core::int;
@#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionInstanceField() → core::int;
@#C1
external static get Extension|extensionStaticField() → core::int;
@#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionStaticField() → core::int;
external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionStaticField() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect
@@ -14,52 +14,52 @@
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t1) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t2) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t3) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t4) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t6) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t7) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t8) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t9) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t10) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t12) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
: super core::Object::•()
;
external get instanceField() → core::int;
- external set instanceField(core::int #t13) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
external get finalInstanceField() → core::int;
external get covariantInstanceField() → core::num;
- external set covariantInstanceField(covariant core::num #t14) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t15) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
@#C1
external static get topLevelField() → core::int;
@#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
@#C1
external static get finalTopLevelField() → core::int;
external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
external static get untypedFinalTopLevelField() → dynamic;
@#C1
external static get Extension|extensionInstanceField() → core::int;
@#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionInstanceField() → core::int;
@#C1
external static get Extension|extensionStaticField() → core::int;
@#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionStaticField() → core::int;
external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionStaticField() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect
@@ -14,52 +14,52 @@
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t1) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t2) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t3) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t4) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t6) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t7) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t8) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t9) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t10) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t12) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
: super core::Object::•()
;
external get instanceField() → core::int;
- external set instanceField(core::int #t13) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
external get finalInstanceField() → core::int;
external get covariantInstanceField() → core::num;
- external set covariantInstanceField(covariant core::num #t14) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t15) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
@#C1
external static get topLevelField() → core::int;
@#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
@#C1
external static get finalTopLevelField() → core::int;
external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
external static get untypedFinalTopLevelField() → dynamic;
@#C1
external static get Extension|extensionInstanceField() → core::int;
@#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionInstanceField() → core::int;
@#C1
external static get Extension|extensionStaticField() → core::int;
@#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionStaticField() → core::int;
external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionStaticField() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect
@@ -14,52 +14,52 @@
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t1) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t2) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t3) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t4) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t6) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
@#C1
external get instanceField() → core::int;
@#C1
- external set instanceField(core::int #t7) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
@#C1
external get finalInstanceField() → core::int;
@#C1
external get covariantInstanceField() → core::num;
@#C1
- external set covariantInstanceField(covariant core::num #t8) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
@#C1
external static get staticField() → core::int;
@#C1
- external static set staticField(core::int #t9) → void;
+ external static set staticField(core::int #externalFieldValue) → void;
@#C1
external static get finalStaticField() → core::int;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t10) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
external static get untypedStaticField() → dynamic;
- external static set untypedStaticField(dynamic #t12) → void;
+ external static set untypedStaticField(dynamic #externalFieldValue) → void;
external static get untypedFinalStaticField() → dynamic;
}
class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
: super core::Object::•()
;
external get instanceField() → core::int;
- external set instanceField(core::int #t13) → void;
+ external set instanceField(core::int #externalFieldValue) → void;
external get finalInstanceField() → core::int;
external get covariantInstanceField() → core::num;
- external set covariantInstanceField(covariant core::num #t14) → void;
+ external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
external get untypedInstanceField() → dynamic;
- external set untypedInstanceField(dynamic #t15) → void;
+ external set untypedInstanceField(dynamic #externalFieldValue) → void;
external get untypedFinalInstanceField() → dynamic;
external get untypedCovariantInstanceField() → dynamic;
- external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+ external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
}
extension Extension on self::A {
get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
@#C1
external static get topLevelField() → core::int;
@#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
@#C1
external static get finalTopLevelField() → core::int;
external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
external static get untypedFinalTopLevelField() → dynamic;
@#C1
external static get Extension|extensionInstanceField() → core::int;
@#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionInstanceField() → core::int;
@#C1
external static get Extension|extensionStaticField() → core::int;
@#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
@#C1
external static get Extension|finalExtensionStaticField() → core::int;
external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
external static get Extension|untypedFinalExtensionStaticField() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect
index 832b31d..bdaf36f 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect
@@ -6,15 +6,15 @@
synthetic constructor •() → self::A
;
external get i1() → core::int;
- external set i1(core::int #t1) → void;
+ external set i1(core::int #externalFieldValue) → void;
external get cx() → dynamic;
- external set cx(covariant dynamic #t2) → void;
+ external set cx(covariant dynamic #externalFieldValue) → void;
external static get s1() → core::int;
- external static set s1(core::int #t3) → void;
+ external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
}
external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect
@@ -7,14 +7,14 @@
: super core::Object::•()
;
external get i1() → core::int;
- external set i1(core::int #t1) → void;
+ external set i1(core::int #externalFieldValue) → void;
external get cx() → dynamic;
- external set cx(covariant dynamic #t2) → void;
+ external set cx(covariant dynamic #externalFieldValue) → void;
external static get s1() → core::int;
- external static set s1(core::int #t3) → void;
+ external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
}
external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect
@@ -7,14 +7,14 @@
: super core::Object::•()
;
external get i1() → core::int;
- external set i1(core::int #t1) → void;
+ external set i1(core::int #externalFieldValue) → void;
external get cx() → dynamic;
- external set cx(covariant dynamic #t2) → void;
+ external set cx(covariant dynamic #externalFieldValue) → void;
external static get s1() → core::int;
- external static set s1(core::int #t3) → void;
+ external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
}
external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect
@@ -7,14 +7,14 @@
: super core::Object::•()
;
external get i1() → core::int;
- external set i1(core::int #t1) → void;
+ external set i1(core::int #externalFieldValue) → void;
external get cx() → dynamic;
- external set cx(covariant dynamic #t2) → void;
+ external set cx(covariant dynamic #externalFieldValue) → void;
external static get s1() → core::int;
- external static set s1(core::int #t3) → void;
+ external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
}
external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect
@@ -7,14 +7,14 @@
: super core::Object::•()
;
external get i1() → core::int;
- external set i1(core::int #t1) → void;
+ external set i1(core::int #externalFieldValue) → void;
external get cx() → dynamic;
- external set cx(covariant dynamic #t2) → void;
+ external set cx(covariant dynamic #externalFieldValue) → void;
external static get s1() → core::int;
- external static set s1(core::int #t3) → void;
+ external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
}
external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
external static get fx() → dynamic;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart b/pkg/front_end/testcases/nnbd/issue40951.dart
new file mode 100644
index 0000000..0f168e8
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2020, 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 {
+ num field1;
+ num field2;
+
+ A() {}
+ A.foo() {}
+ A.bar(this.field1) {}
+ A.baz(this.field1, this.field2) {}
+}
+
+abstract class B {
+ num field1;
+ num field2;
+
+ B() {}
+ B.foo() {}
+ B.bar(this.field1) {}
+ B.baz(this.field1, this.field2) {}
+}
+
+class C {
+ final num? field1;
+ final num? field2;
+
+ C() {}
+ C.foo() {}
+ C.bar(this.field1) {}
+ C.baz(this.field1, this.field2) {}
+}
+
+abstract class D {
+ final num? field1;
+ final num? field2;
+
+ D() {}
+ D.foo() {}
+ D.bar(this.field1) {}
+ D.baz(this.field1, this.field2) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.outline.expect
new file mode 100644
index 0000000..e850cd8
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.outline.expect
@@ -0,0 +1,54 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::A
+ ;
+ constructor foo() → self::A
+ ;
+ constructor bar(core::num field1) → self::A
+ ;
+ constructor baz(core::num field1, core::num field2) → self::A
+ ;
+}
+abstract class B extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::B
+ ;
+ constructor foo() → self::B
+ ;
+ constructor bar(core::num field1) → self::B
+ ;
+ constructor baz(core::num field1, core::num field2) → self::B
+ ;
+}
+class C extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::C
+ ;
+ constructor foo() → self::C
+ ;
+ constructor bar(core::num? field1) → self::C
+ ;
+ constructor baz(core::num? field1, core::num? field2) → self::C
+ ;
+}
+abstract class D extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::D
+ ;
+ constructor foo() → self::D
+ ;
+ constructor bar(core::num? field1) → self::D
+ ;
+ constructor baz(core::num? field1, core::num? field2) → self::D
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor foo() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::A
+ : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::A
+ : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor foo() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::B
+ : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::B
+ : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor foo() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::C
+ : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::C
+ : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor foo() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::D
+ : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::D
+ : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.transformed.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.transformed.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor foo() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::A
+ : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::A
+ : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor foo() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::B
+ : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::B
+ : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor foo() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::C
+ : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::C
+ : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor foo() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::D
+ : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::D
+ : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline.expect
new file mode 100644
index 0000000..611b634
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline.expect
@@ -0,0 +1,37 @@
+class A {
+ num field1;
+ num field2;
+ A() {}
+ A.foo() {}
+ A.bar(this.field1) {}
+ A.baz(this.field1, this.field2) {}
+}
+
+abstract class B {
+ num field1;
+ num field2;
+ B() {}
+ B.foo() {}
+ B.bar(this.field1) {}
+ B.baz(this.field1, this.field2) {}
+}
+
+class C {
+ final num? field1;
+ final num? field2;
+ C() {}
+ C.foo() {}
+ C.bar(this.field1) {}
+ C.baz(this.field1, this.field2) {}
+}
+
+abstract class D {
+ final num? field1;
+ final num? field2;
+ D() {}
+ D.foo() {}
+ D.bar(this.field1) {}
+ D.baz(this.field1, this.field2) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a12b8be
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline_modelled.expect
@@ -0,0 +1,37 @@
+abstract class B {
+ B() {}
+ B.bar(this.field1) {}
+ B.baz(this.field1, this.field2) {}
+ B.foo() {}
+ num field1;
+ num field2;
+}
+
+abstract class D {
+ D() {}
+ D.bar(this.field1) {}
+ D.baz(this.field1, this.field2) {}
+ D.foo() {}
+ final num? field1;
+ final num? field2;
+}
+
+class A {
+ A() {}
+ A.bar(this.field1) {}
+ A.baz(this.field1, this.field2) {}
+ A.foo() {}
+ num field1;
+ num field2;
+}
+
+class C {
+ C() {}
+ C.bar(this.field1) {}
+ C.baz(this.field1, this.field2) {}
+ C.foo() {}
+ final num? field1;
+ final num? field2;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor foo() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::A
+ : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::A
+ : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor foo() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::B
+ : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::B
+ : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor foo() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::C
+ : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::C
+ : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor foo() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::D
+ : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::D
+ : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.transformed.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.transformed.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// A.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+// num field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.foo() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+// B.bar(this.field1) {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+// num field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// C.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D() {}
+// ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+// final num? field1;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.foo() {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+// D.bar(this.field1) {}
+// ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+// final num? field2;
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor foo() → self::A
+ : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::A
+ : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::A
+ : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+ field core::num field1;
+ field core::num field2;
+ constructor •() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor foo() → self::B
+ : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+ constructor bar(core::num field1) → self::B
+ : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num field1, core::num field2) → self::B
+ : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor foo() → self::C
+ : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::C
+ : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::C
+ : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+ final field core::num? field1;
+ final field core::num? field2;
+ constructor •() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor foo() → self::D
+ : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+ constructor bar(core::num? field1) → self::D
+ : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+ constructor baz(core::num? field1, core::num? field2) → self::D
+ : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart b/pkg/front_end/testcases/nnbd/issue42844_1.dart
new file mode 100644
index 0000000..6f9e7d2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, 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 C {
+ Never n; // Error.
+
+ factory C(Never n) = D;
+}
+
+class D implements C {
+ Never n;
+
+ D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.outline.expect
new file mode 100644
index 0000000..a52904f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.outline.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field Never n;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(Never n) → self::C
+ let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ field Never n;
+ constructor •(Never n) → self::D
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.expect
new file mode 100644
index 0000000..9f1d04c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+// Never n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field Never n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(Never n) → self::C
+ let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ field Never n;
+ constructor •(Never n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.transformed.expect
new file mode 100644
index 0000000..7a9d7ad
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.transformed.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+// Never n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field Never n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(Never n) → self::C
+ let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ field Never n;
+ constructor •(Never n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline.expect
new file mode 100644
index 0000000..5449b69
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline.expect
@@ -0,0 +1,11 @@
+class C {
+ Never n;
+ factory C(Never n) = D;
+}
+
+class D implements C {
+ Never n;
+ D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..df335e7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+class C {
+ Never n;
+ factory C(Never n) = D;
+}
+
+class D implements C {
+ D(this.n);
+ Never n;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.expect
new file mode 100644
index 0000000..9f1d04c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+// Never n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field Never n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(Never n) → self::C
+ let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ field Never n;
+ constructor •(Never n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.transformed.expect
new file mode 100644
index 0000000..7a9d7ad
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.transformed.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+// Never n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field Never n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(Never n) → self::C
+ let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ field Never n;
+ constructor •(Never n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart b/pkg/front_end/testcases/nnbd/issue42844_2.dart
new file mode 100644
index 0000000..544e1aa
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, 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 C {
+ final dynamic n; // Error.
+
+ factory C(dynamic n) = D;
+}
+
+class D implements C {
+ final dynamic n;
+
+ D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.outline.expect
new file mode 100644
index 0000000..40df7c4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.outline.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ final field dynamic n;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(dynamic n) → self::C
+ let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ final field dynamic n;
+ constructor •(dynamic n) → self::D
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.expect
new file mode 100644
index 0000000..afaa082
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ final field dynamic n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(dynamic n) → self::C
+ let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ final field dynamic n;
+ constructor •(dynamic n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.transformed.expect
new file mode 100644
index 0000000..4e1efe4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ final field dynamic n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(dynamic n) → self::C
+ let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ final field dynamic n;
+ constructor •(dynamic n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline.expect
new file mode 100644
index 0000000..dc93ebc
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline.expect
@@ -0,0 +1,11 @@
+class C {
+ final dynamic n;
+ factory C(dynamic n) = D;
+}
+
+class D implements C {
+ final dynamic n;
+ D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..8402c4d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+class C {
+ factory C(dynamic n) = D;
+ final dynamic n;
+}
+
+class D implements C {
+ D(this.n);
+ final dynamic n;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.expect
new file mode 100644
index 0000000..afaa082
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ final field dynamic n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(dynamic n) → self::C
+ let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ final field dynamic n;
+ constructor •(dynamic n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..4e1efe4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic n; // Error.
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ final field dynamic n = null;
+ static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+ static factory •(dynamic n) → self::C
+ let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+ final field dynamic n;
+ constructor •(dynamic n) → self::D
+ : self::D::n = n, super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart b/pkg/front_end/testcases/nnbd/issue42967.dart
new file mode 100644
index 0000000..e2e39a7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2020, 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 has no constructors.
+class A {
+ num fieldNonNullableOfA; // Error.
+ late num fieldLateNonNullableOfA; // Ok.
+
+ final dynamic fieldFinalDynamicOfA; // Error.
+ late final dynamic fieldLateFinalDynamicOfA; // Ok.
+}
+
+// Class AbstractA has no constructors.
+abstract class AbstractA {
+ external num fieldExternalNonNullableOfAbstractA; // Ok.
+ abstract num fieldAbstractNonNullableOfAbstractA; // Ok.
+
+ external final dynamic fieldExternalFinalDynamicOfAbstractA; // Ok.
+ abstract final dynamic fieldAbstractFinalDynamicOfAbstractA; // Ok.
+}
+
+
+// Class B has only factory constructors.
+class B {
+ num fieldNonNullableOfB; // Error.
+ late num fieldLateNonNullableOfB; // Ok.
+
+ final dynamic fieldFinalDynamicOfB; // Error.
+ late final dynamic fieldLateFinalDynamicOfB; // Ok.
+
+ factory B() => throw 42;
+}
+
+// Class AbstractB has only factory constructors.
+abstract class AbstractB {
+ external num fieldExternalNonNullableOfAbstractB; // Ok.
+ abstract num fieldAbstractNonNullableOfAbstractB; // Ok.
+
+ external final dynamic fieldExternalFinalDynamicOfAbstractB; // Ok.
+ abstract final dynamic fieldAbstractFinalDynamicOfAbstractB; // Ok.
+}
+
+mixin M {
+ num fieldNonNullableOfM; // Error.
+ late num fieldLateNonNullableOfM; // Ok.
+ external num fieldExternalNonNullableOfM; // Ok.
+ abstract num fieldAbstractNonNullableOfM; // Ok.
+
+ final dynamic fieldFinalDynamicOfM; // Error.
+ late final dynamic fieldLateFinalDynamicOfM; // Ok.
+ external final dynamic fieldExternalFinalDynamicOfM; // Ok.
+ abstract final dynamic fieldAbstractFinalDynamicOfM; // Ok.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.outline.expect
new file mode 100644
index 0000000..12ac249
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.outline.expect
@@ -0,0 +1,54 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num fieldNonNullableOfA;
+ late field core::num fieldLateNonNullableOfA;
+ final field dynamic fieldFinalDynamicOfA;
+ late final [setter] field dynamic fieldLateFinalDynamicOfA;
+ synthetic constructor •() → self::A
+ ;
+}
+abstract class AbstractA extends core::Object {
+ synthetic constructor •() → self::AbstractA
+ ;
+ external get fieldExternalNonNullableOfAbstractA() → core::num;
+ external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+ field core::num fieldNonNullableOfB;
+ late field core::num fieldLateNonNullableOfB;
+ final field dynamic fieldFinalDynamicOfB;
+ late final [setter] field dynamic fieldLateFinalDynamicOfB;
+ static factory •() → self::B
+ ;
+}
+abstract class AbstractB extends core::Object {
+ synthetic constructor •() → self::AbstractB
+ ;
+ external get fieldExternalNonNullableOfAbstractB() → core::num;
+ external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+ field core::num fieldNonNullableOfM;
+ late field core::num fieldLateNonNullableOfM;
+ final field dynamic fieldFinalDynamicOfM;
+ late final [setter] field dynamic fieldLateFinalDynamicOfM;
+ external get fieldExternalNonNullableOfM() → core::num;
+ external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfM() → core::num;
+ abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfM() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num fieldNonNullableOfA = null;
+ late field core::num fieldLateNonNullableOfA;
+ final field dynamic fieldFinalDynamicOfA = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfA;
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractA extends core::Object {
+ synthetic constructor •() → self::AbstractA
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractA() → core::num;
+ external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+ field core::num fieldNonNullableOfB = null;
+ late field core::num fieldLateNonNullableOfB;
+ final field dynamic fieldFinalDynamicOfB = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfB;
+ static factory •() → self::B
+ return throw 42;
+}
+abstract class AbstractB extends core::Object {
+ synthetic constructor •() → self::AbstractB
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractB() → core::num;
+ external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+ field core::num fieldNonNullableOfM = null;
+ late field core::num fieldLateNonNullableOfM;
+ final field dynamic fieldFinalDynamicOfM = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfM;
+ external get fieldExternalNonNullableOfM() → core::num;
+ external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfM() → core::num;
+ abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfM() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.transformed.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num fieldNonNullableOfA = null;
+ late field core::num fieldLateNonNullableOfA;
+ final field dynamic fieldFinalDynamicOfA = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfA;
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractA extends core::Object {
+ synthetic constructor •() → self::AbstractA
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractA() → core::num;
+ external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+ field core::num fieldNonNullableOfB = null;
+ late field core::num fieldLateNonNullableOfB;
+ final field dynamic fieldFinalDynamicOfB = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfB;
+ static factory •() → self::B
+ return throw 42;
+}
+abstract class AbstractB extends core::Object {
+ synthetic constructor •() → self::AbstractB
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractB() → core::num;
+ external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+ field core::num fieldNonNullableOfM = null;
+ late field core::num fieldLateNonNullableOfM;
+ final field dynamic fieldFinalDynamicOfM = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfM;
+ external get fieldExternalNonNullableOfM() → core::num;
+ external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfM() → core::num;
+ abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfM() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.textual_outline.expect
new file mode 100644
index 0000000..003e9d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.textual_outline.expect
@@ -0,0 +1,42 @@
+class A {
+ num fieldNonNullableOfA;
+ late num ;
+ fieldLateNonNullableOfA;
+ final dynamic fieldFinalDynamicOfA;
+ late ;
+ final dynamic fieldLateFinalDynamicOfA;
+}
+abstract class AbstractA {
+ external num fieldExternalNonNullableOfAbstractA;
+ abstract num fieldAbstractNonNullableOfAbstractA;
+ external final dynamic fieldExternalFinalDynamicOfAbstractA;
+ abstract final dynamic fieldAbstractFinalDynamicOfAbstractA;
+}
+class B {
+ num fieldNonNullableOfB;
+ late num ;
+ fieldLateNonNullableOfB;
+ final dynamic fieldFinalDynamicOfB;
+ late ;
+ final dynamic fieldLateFinalDynamicOfB;
+ factory B() => throw 42;
+}
+abstract class AbstractB {
+ external num fieldExternalNonNullableOfAbstractB;
+ abstract num fieldAbstractNonNullableOfAbstractB;
+ external final dynamic fieldExternalFinalDynamicOfAbstractB;
+ abstract final dynamic fieldAbstractFinalDynamicOfAbstractB;
+}
+mixin M {
+ num fieldNonNullableOfM;
+ late num ;
+ fieldLateNonNullableOfM;
+ external num fieldExternalNonNullableOfM;
+ abstract num fieldAbstractNonNullableOfM;
+ final dynamic fieldFinalDynamicOfM;
+ late ;
+ final dynamic fieldLateFinalDynamicOfM;
+ external final dynamic fieldExternalFinalDynamicOfM;
+ abstract final dynamic fieldAbstractFinalDynamicOfM;
+}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num fieldNonNullableOfA = null;
+ late field core::num fieldLateNonNullableOfA;
+ final field dynamic fieldFinalDynamicOfA = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfA;
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractA extends core::Object {
+ synthetic constructor •() → self::AbstractA
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractA() → core::num;
+ external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+ field core::num fieldNonNullableOfB = null;
+ late field core::num fieldLateNonNullableOfB;
+ final field dynamic fieldFinalDynamicOfB = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfB;
+ static factory •() → self::B
+ return throw 42;
+}
+abstract class AbstractB extends core::Object {
+ synthetic constructor •() → self::AbstractB
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractB() → core::num;
+ external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+ field core::num fieldNonNullableOfM = null;
+ late field core::num fieldLateNonNullableOfM;
+ final field dynamic fieldFinalDynamicOfM = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfM;
+ external get fieldExternalNonNullableOfM() → core::num;
+ external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfM() → core::num;
+ abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfM() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.transformed.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfA; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfB; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+// num fieldNonNullableOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+// final dynamic fieldFinalDynamicOfM; // Error.
+// ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::num fieldNonNullableOfA = null;
+ late field core::num fieldLateNonNullableOfA;
+ final field dynamic fieldFinalDynamicOfA = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfA;
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractA extends core::Object {
+ synthetic constructor •() → self::AbstractA
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractA() → core::num;
+ external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+ field core::num fieldNonNullableOfB = null;
+ late field core::num fieldLateNonNullableOfB;
+ final field dynamic fieldFinalDynamicOfB = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfB;
+ static factory •() → self::B
+ return throw 42;
+}
+abstract class AbstractB extends core::Object {
+ synthetic constructor •() → self::AbstractB
+ : super core::Object::•()
+ ;
+ external get fieldExternalNonNullableOfAbstractB() → core::num;
+ external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+ abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+ field core::num fieldNonNullableOfM = null;
+ late field core::num fieldLateNonNullableOfM;
+ final field dynamic fieldFinalDynamicOfM = null;
+ late final [setter] field dynamic fieldLateFinalDynamicOfM;
+ external get fieldExternalNonNullableOfM() → core::num;
+ external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+ abstract get fieldAbstractNonNullableOfM() → core::num;
+ abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+ external get fieldExternalFinalDynamicOfM() → dynamic;
+ abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
@@ -14,15 +14,24 @@
// static int staticFieldOfM; // Error.
// ^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// A.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
// int fieldOfA; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
// X fieldOfB; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
// Y fieldOfB2; // Error.
// ^^^^^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
@@ -14,15 +14,24 @@
// static int staticFieldOfM; // Error.
// ^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// A.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
// int fieldOfA; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
// X fieldOfB; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
// Y fieldOfB2; // Error.
// ^^^^^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
@@ -14,15 +14,24 @@
// static int staticFieldOfM; // Error.
// ^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// A.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
// int fieldOfA; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
// X fieldOfB; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
// Y fieldOfB2; // Error.
// ^^^^^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
@@ -14,15 +14,24 @@
// static int staticFieldOfM; // Error.
// ^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// A.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
// int fieldOfA; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
// X fieldOfB; // Error.
// ^^^^^^^^
//
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// B.foo();
+// ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
// Y fieldOfB2; // Error.
// ^^^^^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect
@@ -21,7 +21,10 @@
// int field;
// ^^^^^
//
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// Class2.constructor1();
+// ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
// int field;
// ^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect
@@ -21,7 +21,10 @@
// int field;
// ^^^^^
//
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// Class2.constructor1();
+// ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
// int field;
// ^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect
@@ -21,7 +21,10 @@
// int field;
// ^^^^^
//
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// Class2.constructor1();
+// ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
// int field;
// ^^^^^
//
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect
@@ -21,7 +21,10 @@
// int field;
// ^^^^^
//
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// Class2.constructor1();
+// ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
// int field;
// ^^^^^
//
diff --git a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect
index 1fcac9d..da6a3f4 100644
--- a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect
+++ b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect
@@ -75,8 +75,16 @@
self::Class::_#nullableStaticFieldWithInitializer2#isSet = true;
self::Class::_#nullableStaticFieldWithInitializer2 = #t6;
}
- static get nonNullableStaticFinalFieldWithInitializer1() → core::int
- return let final core::int? #t7 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t7.==(null) ?{core::int} let final core::int #t8 = self::init<core::int>(73) in self::Class::_#nonNullableStaticFinalFieldWithInitializer1.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.") : #t7{core::int};
+ static get nonNullableStaticFinalFieldWithInitializer1() → core::int {
+ if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet) {
+ final core::int #t7 = self::init<core::int>(73);
+ if(self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t7;
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet = true;
+ }
+ return let final core::int? #t8 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t8{core::int};
+ }
static get nullableStaticFinalFieldWithInitializer1() → core::int? {
if(!self::Class::_#nullableStaticFinalFieldWithInitializer1#isSet) {
final core::int? #t9 = self::init<core::int?>(19);
@@ -98,8 +106,16 @@
self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init#isSet = true;
self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init = #t11;
}
- static get nonNullableStaticFinalFieldWithInitializer2() → core::int
- return let final core::int? #t12 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t12.==(null) ?{core::int} let final core::int #t13 = (let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t15 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t14.{core::num::+}(1) in #t14).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87 in self::Class::_#nonNullableStaticFinalFieldWithInitializer2.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t13 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.") : #t12{core::int};
+ static get nonNullableStaticFinalFieldWithInitializer2() → core::int {
+ if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet) {
+ final core::int #t12 = (let final core::int #t13 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87;
+ if(self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t12;
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet = true;
+ }
+ return let final core::int? #t15 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t15{core::int};
+ }
static get nullableStaticFinalFieldWithInitializer2Init() → core::int {
if(!self::Class::_#nullableStaticFinalFieldWithInitializer2Init#isSet) {
self::Class::_#nullableStaticFinalFieldWithInitializer2Init = 0;
@@ -193,8 +209,16 @@
self::_#nullableTopLevelFieldWithInitializer2#isSet = true;
self::_#nullableTopLevelFieldWithInitializer2 = #t26;
}
-static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int
- return let final core::int? #t27 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t27.==(null) ?{core::int} let final core::int #t28 = self::init<core::int>(87) in self::_#nonNullableFinalTopLevelFieldWithInitializer1.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.") : #t27{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int {
+ if(!self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet) {
+ final core::int #t27 = self::init<core::int>(87);
+ if(self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.");
+ self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t27;
+ self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet = true;
+ }
+ return let final core::int? #t28 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t28{core::int};
+}
static get nullableFinalTopLevelFieldWithInitializer1() → core::int? {
if(!self::_#nullableFinalTopLevelFieldWithInitializer1#isSet) {
final core::int? #t29 = self::init<core::int?>(32);
@@ -216,8 +240,16 @@
self::_#nonNullableFinalTopLevelFieldWithInitializer2Init#isSet = true;
self::_#nonNullableFinalTopLevelFieldWithInitializer2Init = #t31;
}
-static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int
- return let final core::int? #t32 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t32.==(null) ?{core::int} let final core::int #t33 = (let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t35 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t34.{core::num::+}(1) in #t34).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87 in self::_#nonNullableFinalTopLevelFieldWithInitializer2.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t33 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.") : #t32{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int {
+ if(!self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet) {
+ final core::int #t32 = (let final core::int #t33 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t33.{core::num::+}(1) in #t33).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87;
+ if(self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.");
+ self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t32;
+ self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet = true;
+ }
+ return let final core::int? #t35 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t35{core::int};
+}
static get nullableFinalTopLevelFieldWithInitializer2Init() → core::int {
if(!self::_#nullableFinalTopLevelFieldWithInitializer2Init#isSet) {
self::_#nullableFinalTopLevelFieldWithInitializer2Init = 0;
diff --git a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect
index 1fcac9d..da6a3f4 100644
--- a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect
@@ -75,8 +75,16 @@
self::Class::_#nullableStaticFieldWithInitializer2#isSet = true;
self::Class::_#nullableStaticFieldWithInitializer2 = #t6;
}
- static get nonNullableStaticFinalFieldWithInitializer1() → core::int
- return let final core::int? #t7 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t7.==(null) ?{core::int} let final core::int #t8 = self::init<core::int>(73) in self::Class::_#nonNullableStaticFinalFieldWithInitializer1.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.") : #t7{core::int};
+ static get nonNullableStaticFinalFieldWithInitializer1() → core::int {
+ if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet) {
+ final core::int #t7 = self::init<core::int>(73);
+ if(self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t7;
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet = true;
+ }
+ return let final core::int? #t8 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t8{core::int};
+ }
static get nullableStaticFinalFieldWithInitializer1() → core::int? {
if(!self::Class::_#nullableStaticFinalFieldWithInitializer1#isSet) {
final core::int? #t9 = self::init<core::int?>(19);
@@ -98,8 +106,16 @@
self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init#isSet = true;
self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init = #t11;
}
- static get nonNullableStaticFinalFieldWithInitializer2() → core::int
- return let final core::int? #t12 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t12.==(null) ?{core::int} let final core::int #t13 = (let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t15 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t14.{core::num::+}(1) in #t14).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87 in self::Class::_#nonNullableStaticFinalFieldWithInitializer2.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t13 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.") : #t12{core::int};
+ static get nonNullableStaticFinalFieldWithInitializer2() → core::int {
+ if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet) {
+ final core::int #t12 = (let final core::int #t13 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87;
+ if(self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.");
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t12;
+ self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet = true;
+ }
+ return let final core::int? #t15 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t15{core::int};
+ }
static get nullableStaticFinalFieldWithInitializer2Init() → core::int {
if(!self::Class::_#nullableStaticFinalFieldWithInitializer2Init#isSet) {
self::Class::_#nullableStaticFinalFieldWithInitializer2Init = 0;
@@ -193,8 +209,16 @@
self::_#nullableTopLevelFieldWithInitializer2#isSet = true;
self::_#nullableTopLevelFieldWithInitializer2 = #t26;
}
-static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int
- return let final core::int? #t27 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t27.==(null) ?{core::int} let final core::int #t28 = self::init<core::int>(87) in self::_#nonNullableFinalTopLevelFieldWithInitializer1.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.") : #t27{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int {
+ if(!self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet) {
+ final core::int #t27 = self::init<core::int>(87);
+ if(self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.");
+ self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t27;
+ self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet = true;
+ }
+ return let final core::int? #t28 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t28{core::int};
+}
static get nullableFinalTopLevelFieldWithInitializer1() → core::int? {
if(!self::_#nullableFinalTopLevelFieldWithInitializer1#isSet) {
final core::int? #t29 = self::init<core::int?>(32);
@@ -216,8 +240,16 @@
self::_#nonNullableFinalTopLevelFieldWithInitializer2Init#isSet = true;
self::_#nonNullableFinalTopLevelFieldWithInitializer2Init = #t31;
}
-static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int
- return let final core::int? #t32 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t32.==(null) ?{core::int} let final core::int #t33 = (let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t35 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t34.{core::num::+}(1) in #t34).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87 in self::_#nonNullableFinalTopLevelFieldWithInitializer2.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t33 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.") : #t32{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int {
+ if(!self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet) {
+ final core::int #t32 = (let final core::int #t33 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t33.{core::num::+}(1) in #t33).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87;
+ if(self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.");
+ self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t32;
+ self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet = true;
+ }
+ return let final core::int? #t35 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t35{core::int};
+}
static get nullableFinalTopLevelFieldWithInitializer2Init() → core::int {
if(!self::_#nullableFinalTopLevelFieldWithInitializer2Init#isSet) {
self::_#nullableFinalTopLevelFieldWithInitializer2Init = 0;
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 955761c..6c237da 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -171,6 +171,7 @@
instantiate_to_bound/non_simple_class_parametrized_typedef_cycle: RuntimeError # Expected
instantiate_to_bound/non_simple_generic_function_in_bound_regress: RuntimeError # Expected
late_lowering/covariant_late_field: TypeCheckError
+late_lowering/initializer_rewrite_from_opt_out: RuntimeError # Test is inherently mixed mode
late_lowering/non_nullable_from_opt_out: RuntimeError # Test is inherently mixed mode
nnbd/covariant_late_field: TypeCheckError
nnbd/issue41180: RuntimeError # Strong mode runtime checking fails due to mixed strong mode.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index ccd0d03..825cdf1 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -169,6 +169,7 @@
instantiate_to_bound/non_simple_class_parametrized_typedef_cycle: RuntimeError
instantiate_to_bound/non_simple_generic_function_in_bound_regress: RuntimeError
late_lowering/covariant_late_field: TypeCheckError
+late_lowering/initializer_rewrite_from_opt_out: RuntimeError # Test is inherently mixed mode
late_lowering/non_nullable_from_opt_out: RuntimeError # Test is inherently mixed mode
nnbd/covariant_late_field: TypeCheckError
nnbd/issue41180: RuntimeError
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 5565670..bc6e72f 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -131,6 +131,7 @@
late_lowering/covariant_late_field: FormatterCrash
late_lowering/infer_late_field_type: FormatterCrash
late_lowering/initializer_rewrite: FormatterCrash
+late_lowering/initializer_rewrite_from_opt_out: FormatterCrash
late_lowering/instance_field_with_initializer: FormatterCrash
late_lowering/instance_field_without_initializer: FormatterCrash
late_lowering/instance_final_field_without_initializer: FormatterCrash
@@ -157,6 +158,7 @@
late_lowering/later: FormatterCrash
late_lowering/override: FormatterCrash
late_lowering/override_getter_setter: FormatterCrash
+late_lowering_sentinel/late_fields: FormatterCrash
late_lowering/uninitialized_non_nullable_late_fields: FormatterCrash
nnbd/abstract_field_errors: FormatterCrash
nnbd/covariant_late_field: FormatterCrash
@@ -170,6 +172,7 @@
nnbd/issue40805: FormatterCrash
nnbd/issue41349: FormatterCrash
nnbd/issue41597: FormatterCrash
+nnbd/issue42967: FormatterCrash
nnbd/issue43278: FormatterCrash
nnbd/late: FormatterCrash
nnbd/later: FormatterCrash
@@ -234,4 +237,3 @@
variance/generic_covariance_sound_variance: FormatterCrash
variance/mixin_type_parameter_modifier: FormatterCrash
variance/unconstrained_inference: FormatterCrash
-
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index c95b0a2..9e583c2 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -342,6 +342,7 @@
CompilerOptions _compilerOptions;
BytecodeOptions _bytecodeOptions;
+ ProcessedOptions _processedOptions;
FileSystem _fileSystem;
Uri _mainSource;
ArgResults _options;
@@ -516,6 +517,7 @@
_compilerOptions = compilerOptions;
_bytecodeOptions = bytecodeOptions;
+ _processedOptions = ProcessedOptions(options: compilerOptions);
KernelCompilationResults results;
IncrementalSerializer incrementalSerializer;
@@ -972,14 +974,21 @@
final String boundaryKey = Uuid().generateV4();
_outputStream.writeln('result $boundaryKey');
+ _processedOptions.ticker.logMs('Compiling expression to JavaScript');
+
var kernel2jsCompiler = _bundler.compilers[moduleName];
Component component = _generator.lastKnownGoodComponent;
component.computeCanonicalNames();
+
+ _processedOptions.ticker.logMs('Computed component');
+
var evaluator = new ExpressionCompiler(
- _generator.generator, kernel2jsCompiler, component,
- verbose: _compilerOptions.verbose,
- onDiagnostic: _compilerOptions.onDiagnostic,
- errors: errors);
+ _compilerOptions,
+ errors,
+ _generator.generator,
+ kernel2jsCompiler,
+ component,
+ );
var procedure = await evaluator.compileExpressionToJs(libraryUri, line,
column, jsModules, jsFrameValues, moduleName, expression);
@@ -990,6 +999,8 @@
// rename to _outputFileName?
await File(_kernelBinaryFilename).writeAsString(result);
+ _processedOptions.ticker.logMs('Compiled expression to JavaScript');
+
_outputStream
.writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index cc60986..832f966 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -71,6 +71,8 @@
Procedure _iterableGetIterator;
Procedure _iteratorMoveNext;
Procedure _iteratorGetCurrent;
+ Procedure _isSentinelMethod;
+ Procedure _createSentinelMethod;
Class _internalSymbolClass;
@@ -497,6 +499,16 @@
index.getMember('dart:core', 'bool', 'fromEnvironment');
}
+ Procedure get createSentinelMethod {
+ return _createSentinelMethod ??=
+ index.getTopLevelMember('dart:_internal', 'createSentinel');
+ }
+
+ Procedure get isSentinelMethod {
+ return _isSentinelMethod ??=
+ index.getTopLevelMember('dart:_internal', 'isSentinel');
+ }
+
InterfaceType get objectLegacyRawType {
return _objectLegacyRawType ??= _legacyRawTypes[objectClass] ??=
new InterfaceType(objectClass, Nullability.legacy, const <DartType>[]);
diff --git a/pkg/kernel/lib/default_language_version.dart b/pkg/kernel/lib/default_language_version.dart
index 6b7b18c..eb90980 100644
--- a/pkg/kernel/lib/default_language_version.dart
+++ b/pkg/kernel/lib/default_language_version.dart
@@ -9,4 +9,4 @@
import "ast.dart";
-Version defaultLanguageVersion = const Version(2, 10);
+Version defaultLanguageVersion = const Version(2, 11);
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 1aa2f44..93ea3c9 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -14,6 +14,7 @@
class TargetFlags {
final bool trackWidgetCreation;
final bool forceLateLoweringForTesting;
+ final bool forceLateLoweringSentinelForTesting;
final bool forceStaticFieldLoweringForTesting;
final bool forceNoExplicitGetterCallsForTesting;
final bool enableNullSafety;
@@ -21,6 +22,7 @@
const TargetFlags(
{this.trackWidgetCreation = false,
this.forceLateLoweringForTesting = false,
+ this.forceLateLoweringSentinelForTesting = false,
this.forceStaticFieldLoweringForTesting = false,
this.forceNoExplicitGetterCallsForTesting = false,
this.enableNullSafety = false});
@@ -30,6 +32,8 @@
return other is TargetFlags &&
trackWidgetCreation == other.trackWidgetCreation &&
forceLateLoweringForTesting == other.forceLateLoweringForTesting &&
+ forceLateLoweringSentinelForTesting ==
+ other.forceLateLoweringSentinelForTesting &&
forceStaticFieldLoweringForTesting ==
other.forceStaticFieldLoweringForTesting &&
forceNoExplicitGetterCallsForTesting ==
@@ -43,6 +47,8 @@
hash = 0x3fffffff &
(hash * 31 + (hash ^ forceLateLoweringForTesting.hashCode));
hash = 0x3fffffff &
+ (hash * 31 + (hash ^ forceLateLoweringSentinelForTesting.hashCode));
+ hash = 0x3fffffff &
(hash * 31 + (hash ^ forceStaticFieldLoweringForTesting.hashCode));
hash = 0x3fffffff &
(hash * 31 + (hash ^ forceNoExplicitGetterCallsForTesting.hashCode));
@@ -282,6 +288,13 @@
/// details.
bool get supportsLateFields;
+ /// If `true`, the backend supports creation and checking of a sentinel value
+ /// for uninitialized late fields and variables through the `createSentinel`
+ /// and `isSentinel` methods in `dart:_internal`.
+ ///
+ /// If `true` this is used when [supportsLateFields] is `false`.
+ bool get supportsLateLoweringSentinel;
+
/// Whether static fields with initializers in nnbd libraries should be
/// encoded using the late field lowering.
bool get useStaticFieldLowering;
@@ -349,6 +362,10 @@
bool get supportsLateFields => !flags.forceLateLoweringForTesting;
@override
+ bool get supportsLateLoweringSentinel =>
+ flags.forceLateLoweringSentinelForTesting;
+
+ @override
bool get useStaticFieldLowering => flags.forceStaticFieldLoweringForTesting;
@override
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index 9e27c00..d80e12b 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.3.0-nullsafety.4
+
+* Introduce `@internal` to annotate elements that should not be used outside of
+ the package in which the element is declared.
+
## 1.3.0-nullsafety.3
* Allow 2.10 stable and 2.11.0 dev SDK versions.
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 11652e1..c6dff3b 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -126,6 +126,20 @@
/// class that has this annotation is not immutable.
const Immutable immutable = Immutable();
+/// Used to annotate a declaration which should only be used from within the
+/// package in which it is declared, and which should not be exposed from said
+/// package's public API.
+///
+/// Tools, such as the analyzer, can provide feedback if
+///
+/// * the declaration is declared in a package's public API, or is exposed from
+/// a package's public API, or
+/// * the declaration is private, an unnamed extension, a static member of a
+/// private class, mixin, or extension, a value of a private enum, or a
+/// constructor of a private class, or
+/// * the declaration is referenced outside the package in which it is declared.
+const _Internal internal = _Internal();
+
/// Used to annotate a test framework function that runs a single test.
///
/// Tools, such as IDEs, can show invocations of such function in a file
@@ -257,15 +271,15 @@
/// * the member is referenced outside of the defining library.
const _VisibleForOverriding visibleForOverriding = _VisibleForOverriding();
-/// Used to annotate a declaration was made public, so that it is more visible
-/// than otherwise necessary, to make code testable.
+/// Used to annotate a declaration that was made public, so that it is more
+/// visible than otherwise necessary, to make code testable.
///
/// Tools, such as the analyzer, can provide feedback if
///
/// * the annotation is associated with a declaration not in the `lib` folder
/// of a package, or a private declaration, or a declaration in an unnamed
/// static extension, or
-/// * the declaration is referenced outside of its the defining library or a
+/// * the declaration is referenced outside of its defining library or a
/// library which is in the `test` folder of the defining package.
const _VisibleForTesting visibleForTesting = _VisibleForTesting();
@@ -326,6 +340,10 @@
const _Factory();
}
+class _Internal {
+ const _Internal();
+}
+
class _IsTest {
const _IsTest();
}
diff --git a/pkg/native_stack_traces/analysis_options.yaml b/pkg/native_stack_traces/analysis_options.yaml
index 84a5e26..486705d 100644
--- a/pkg/native_stack_traces/analysis_options.yaml
+++ b/pkg/native_stack_traces/analysis_options.yaml
@@ -1 +1 @@
-include: package:pedantic/analysis_options.1.8.0.yaml
+include: package:pedantic/analysis_options.1.9.0.yaml
diff --git a/pkg/native_stack_traces/bin/decode.dart b/pkg/native_stack_traces/bin/decode.dart
index 2458e16..9a7aee0 100644
--- a/pkg/native_stack_traces/bin/decode.dart
+++ b/pkg/native_stack_traces/bin/decode.dart
@@ -123,7 +123,7 @@
Options specific to the find command:
${_findParser.usage}''';
-final _usages = <String, String>{
+final _usages = <String?, String>{
null: _mainUsage,
'': _mainUsage,
'help': _helpUsage,
@@ -133,7 +133,7 @@
const int _badUsageExitCode = 1;
-void errorWithUsage(String message, {String command}) {
+void errorWithUsage(String message, {String? command}) {
print("Error: $message.\n");
print(_usages[command]);
io.exitCode = _badUsageExitCode;
@@ -156,7 +156,7 @@
}
}
-Dwarf _loadFromFile(String original, Function(String) usageError) {
+Dwarf? _loadFromFile(String? original, Function(String) usageError) {
if (original == null) {
usageError('must provide -d/--debug');
return null;
@@ -178,7 +178,7 @@
final bool forceHexadecimal = options['force_hexadecimal'];
void usageError(String message) => errorWithUsage(message, command: 'find');
- int parseIntAddress(String s) {
+ int? tryParseIntAddress(String s) {
if (!forceHexadecimal && !s.startsWith("0x")) {
final decimal = int.tryParse(s);
if (decimal != null) return decimal;
@@ -186,11 +186,11 @@
return int.tryParse(s.startsWith("0x") ? s.substring(2) : s, radix: 16);
}
- PCOffset convertAddress(StackTraceHeader header, String s) {
+ PCOffset? convertAddress(StackTraceHeader header, String s) {
final parsedOffset = tryParseSymbolOffset(s, forceHexadecimal);
if (parsedOffset != null) return parsedOffset;
- final address = parseIntAddress(s);
+ final address = tryParseIntAddress(s);
if (address != null) return header.offsetOf(address);
return null;
@@ -209,20 +209,22 @@
int vmStart = dwarf.vmStartAddress;
if (options['vm_start'] != null) {
- vmStart = parseIntAddress(options['vm_start']);
- if (vmStart == null) {
+ final address = tryParseIntAddress(options['vm_start']);
+ if (address == null) {
return usageError('could not parse VM start address '
'${options['vm_start']}');
}
+ vmStart = address;
}
int isolateStart = dwarf.isolateStartAddress;
if (options['isolate_start'] != null) {
- isolateStart = parseIntAddress(options['isolate_start']);
- if (isolateStart == null) {
+ final address = tryParseIntAddress(options['isolate_start']);
+ if (address == null) {
return usageError('could not parse isolate start address '
'${options['isolate_start']}');
}
+ isolateStart = address;
}
final header = StackTraceHeader(isolateStart, vmStart);
diff --git a/pkg/native_stack_traces/lib/src/convert.dart b/pkg/native_stack_traces/lib/src/convert.dart
index 8f81c17..b6d96b4 100644
--- a/pkg/native_stack_traces/lib/src/convert.dart
+++ b/pkg/native_stack_traces/lib/src/convert.dart
@@ -27,11 +27,11 @@
//
// Returns a new [StackTraceHeader] if [line] contains the needed header
// information, otherwise returns `null`.
-StackTraceHeader _parseInstructionsLine(String line) {
+StackTraceHeader? _parseInstructionsLine(String line) {
final match = _headerEndRE.firstMatch(line);
if (match == null) return null;
- final isolateAddr = int.parse(match[1], radix: 16);
- final vmAddr = int.parse(match[2], radix: 16);
+ final isolateAddr = int.parse(match[1]!, radix: 16);
+ final vmAddr = int.parse(match[2]!, radix: 16);
return StackTraceHeader(isolateAddr, vmAddr);
}
@@ -81,12 +81,12 @@
/// any hexdecimal digits will be parsed as decimal.
///
/// Returns null if the string is not of the expected format.
-PCOffset tryParseSymbolOffset(String s, [bool forceHexadecimal = false]) {
+PCOffset? tryParseSymbolOffset(String s, [bool forceHexadecimal = false]) {
final match = _symbolOffsetRE.firstMatch(s);
if (match == null) return null;
- final symbolString = match.namedGroup('symbol');
- final offsetString = match.namedGroup('offset');
- int offset;
+ final symbolString = match.namedGroup('symbol')!;
+ final offsetString = match.namedGroup('offset')!;
+ int? offset;
if (!forceHexadecimal && !offsetString.startsWith("0x")) {
offset = int.tryParse(offsetString);
}
@@ -108,9 +108,9 @@
return null;
}
-PCOffset _retrievePCOffset(StackTraceHeader header, RegExpMatch match) {
+PCOffset? _retrievePCOffset(StackTraceHeader? header, RegExpMatch? match) {
if (match == null) return null;
- final restString = match.namedGroup('rest');
+ final restString = match.namedGroup('rest')!;
// Try checking for symbol information first, since we don't need the header
// information to translate it.
if (restString.isNotEmpty) {
@@ -120,8 +120,8 @@
// If we're parsing the absolute address, we can only convert it into
// a PCOffset if we saw the instructions line of the stack trace header.
if (header != null) {
- final addressString = match.namedGroup('absolute');
- final address = int.tryParse(addressString, radix: 16);
+ final addressString = match.namedGroup('absolute')!;
+ final address = int.parse(addressString, radix: 16);
return header.offsetOf(address);
}
// If all other cases failed, check for a virtual address. Until this package
@@ -130,7 +130,7 @@
// debugging information, the other methods should be tried first.
final virtualString = match.namedGroup('virtual');
if (virtualString != null) {
- final address = int.tryParse(virtualString, radix: 16);
+ final address = int.parse(virtualString, radix: 16);
return PCOffset(address, InstructionsSection.none);
}
return null;
@@ -138,7 +138,7 @@
/// The [PCOffset]s for frames of the non-symbolic stack traces in [lines].
Iterable<PCOffset> collectPCOffsets(Iterable<String> lines) sync* {
- StackTraceHeader header;
+ StackTraceHeader? header;
for (var line in lines) {
final parsedHeader = _parseInstructionsLine(line);
if (parsedHeader != null) {
@@ -184,7 +184,7 @@
Stream<String> bind(Stream<String> stream) async* {
int depth = 0;
- StackTraceHeader header;
+ StackTraceHeader? header;
await for (final line in stream) {
final parsedHeader = _parseInstructionsLine(line);
if (parsedHeader != null) {
@@ -207,7 +207,7 @@
if (callInfo.isEmpty) continue;
// Output the lines for the symbolic frame with the prefix found on the
// original non-symbolic frame line.
- final prefix = line.substring(0, lineMatch.start);
+ final prefix = line.substring(0, lineMatch!.start);
for (final call in callInfo) {
yield prefix + _stackTracePiece(call, depth++);
}
diff --git a/pkg/native_stack_traces/lib/src/dwarf.dart b/pkg/native_stack_traces/lib/src/dwarf.dart
index fd0911b..e8d7ef1 100644
--- a/pkg/native_stack_traces/lib/src/dwarf.dart
+++ b/pkg/native_stack_traces/lib/src/dwarf.dart
@@ -122,7 +122,7 @@
_Attribute._(this.name, this.form);
- static _Attribute fromReader(Reader reader) {
+ static _Attribute? fromReader(Reader reader) {
final nameInt = reader.readLEB128EncodedInteger();
final formInt = reader.readLEB128EncodedInteger();
if (nameInt == 0 && formInt == 0) return null;
@@ -132,7 +132,7 @@
if (!_attributeForms.containsKey(formInt)) {
throw FormatException("Unexpected DW_FORM value 0x${paddedHex(formInt)}");
}
- return _Attribute._(_attributeNames[nameInt], _attributeForms[formInt]);
+ return _Attribute._(_attributeNames[nameInt]!, _attributeForms[formInt]!);
}
Object read(Reader reader, CompilationUnitHeader header) {
@@ -148,25 +148,24 @@
case _AttributeForm.reference4:
return reader.readBytes(4);
}
- return null;
}
- String valueToString(Object value, [CompilationUnit unit]) {
+ String valueToString(Object value, [CompilationUnit? unit]) {
switch (form) {
case _AttributeForm.string:
return value as String;
case _AttributeForm.address:
- return '0x' + paddedHex(value as int, unit?.header?.addressSize ?? 0);
+ return '0x' + paddedHex(value as int, unit?.header.addressSize ?? 0);
case _AttributeForm.sectionOffset:
return paddedHex(value as int, 4);
case _AttributeForm.constant:
return value.toString();
case _AttributeForm.reference4:
- final unresolvedValue = paddedHex(value as int, 4);
- final name = unit?.nameOfOrigin(value as int) ?? "(unresolved)";
+ final intValue = value as int;
+ final unresolvedValue = paddedHex(intValue, 4);
+ final name = unit?.nameOfOrigin(intValue) ?? "<unresolved>";
return '0x${unresolvedValue} (origin: ${name})';
}
- return "<unknown>";
}
}
@@ -182,14 +181,14 @@
static const _DW_CHILDREN_no = 0x00;
static const _DW_CHILDREN_yes = 0x01;
- static _Abbreviation fromReader(Reader reader) {
+ static _Abbreviation? fromReader(Reader reader) {
final code = reader.readLEB128EncodedInteger();
if (code == 0) return null;
final tagInt = reader.readLEB128EncodedInteger();
if (!_tags.containsKey(tagInt)) {
throw FormatException("Unexpected DW_TAG value 0x${paddedHex(tagInt)}");
}
- final tag = _tags[tagInt];
+ final tag = _tags[tagInt]!;
final childrenByte = reader.readByte();
if (childrenByte != _DW_CHILDREN_no && childrenByte != _DW_CHILDREN_yes) {
throw FormatException("Expected DW_CHILDREN_no or DW_CHILDREN_yes: "
@@ -210,9 +209,9 @@
for (final attribute in attributes) {
buffer
..write(' ')
- ..write(_attributeNameStrings[attribute.name])
+ ..write(_attributeNameStrings[attribute.name]!)
..write(': ')
- ..writeln(_attributeFormStrings[attribute.form]);
+ ..writeln(_attributeFormStrings[attribute.form]!);
}
}
@@ -230,9 +229,9 @@
_AbbreviationsTable._(this._abbreviations);
bool containsKey(int code) => _abbreviations.containsKey(code);
- _Abbreviation operator [](int code) => _abbreviations[code];
+ _Abbreviation? operator [](int code) => _abbreviations[code];
- static _AbbreviationsTable fromReader(Reader reader) {
+ static _AbbreviationsTable? fromReader(Reader reader) {
final abbreviations = Map.fromEntries(reader
.readRepeated(_Abbreviation.fromReader)
.map((abbr) => MapEntry(abbr.code, abbr)));
@@ -241,14 +240,14 @@
void writeToStringBuffer(StringBuffer buffer) {
buffer..writeln('Abbreviations table:')..writeln();
- for (final key in _abbreviations.keys) {
+ _abbreviations.forEach((key, abbreviation) {
buffer
..write(' ')
..write(key)
..writeln(':');
- _abbreviations[key].writeToStringBuffer(buffer);
+ abbreviation.writeToStringBuffer(buffer);
buffer..writeln();
- }
+ });
}
@override
@@ -268,7 +267,7 @@
DebugInformationEntry._(this.code, this.attributes, this.children);
- static DebugInformationEntry fromReader(
+ static DebugInformationEntry? fromReader(
Reader reader, CompilationUnitHeader header) {
final code = reader.readLEB128EncodedInteger();
// DIEs with an abbreviation table index of 0 are list end markers.
@@ -276,81 +275,83 @@
if (!header.abbreviations.containsKey(code)) {
throw FormatException("Unknown abbreviation code 0x${paddedHex(code)}");
}
- final abbreviation = header.abbreviations[code];
+ final abbreviation = header.abbreviations[code]!;
final attributes = <_Attribute, Object>{};
for (final attribute in abbreviation.attributes) {
attributes[attribute] = attribute.read(reader, header);
}
- Map<int, DebugInformationEntry> children;
+ final children = <int, DebugInformationEntry>{};
if (abbreviation.children) {
- children = Map.fromEntries(reader.readRepeatedWithOffsets(
+ children.addEntries(reader.readRepeatedWithOffsets(
(r) => DebugInformationEntry.fromReader(r, header),
absolute: true));
}
- assert((children != null) == abbreviation.children);
return DebugInformationEntry._(code, attributes, children);
}
- _Attribute _namedAttribute(_AttributeName name) => attributes.keys
- .firstWhere((_Attribute k) => k.name == name, orElse: () => null);
+ _Attribute? _namedAttribute(_AttributeName name) {
+ for (final attribute in attributes.keys) {
+ if (attribute.name == name) {
+ return attribute;
+ }
+ }
+ return null;
+ }
bool containsKey(_AttributeName name) => _namedAttribute(name) != null;
- Object operator [](_AttributeName name) => attributes[_namedAttribute(name)];
+ Object? operator [](_AttributeName name) => attributes[_namedAttribute(name)];
- int get abstractOrigin => this[_AttributeName.abstractOrigin] as int;
+ int? get sectionOffset => this[_AttributeName.statementList] as int?;
- int get lowPC => this[_AttributeName.lowProgramCounter] as int;
+ int? get abstractOrigin => this[_AttributeName.abstractOrigin] as int?;
- int get highPC => this[_AttributeName.highProgramCounter] as int;
+ int? get lowPC => this[_AttributeName.lowProgramCounter] as int?;
+
+ int? get highPC => this[_AttributeName.highProgramCounter] as int?;
bool containsPC(int virtualAddress) =>
- lowPC != null && lowPC <= virtualAddress && virtualAddress < highPC;
+ (lowPC ?? 0) <= virtualAddress && virtualAddress < (highPC ?? -1);
- String get name => this[_AttributeName.name] as String;
+ String? get name => this[_AttributeName.name] as String?;
- int get callFileIndex => this[_AttributeName.callFile] as int;
+ int? get callFileIndex => this[_AttributeName.callFile] as int?;
- int get callLine => this[_AttributeName.callLine] as int;
+ int? get callLine => this[_AttributeName.callLine] as int?;
- // We don't assume that call columns are present for backwards compatibility.
- int get callColumn => containsKey(_AttributeName.callColumn)
- ? this[_AttributeName.callColumn] as int
- : 0;
+ int? get callColumn => this[_AttributeName.callColumn] as int?;
- List<CallInfo> callInfo(
+ List<CallInfo>? callInfo(
CompilationUnit unit, LineNumberProgram lineNumberProgram, int address) {
String callFilename(int index) =>
- lineNumberProgram.header.filesInfo[index].name;
+ lineNumberProgram.header.filesInfo[index]?.name ?? '<unknown file>';
if (!containsPC(address)) return null;
- final tag = unit.header.abbreviations[code].tag;
+ final tag = unit.header.abbreviations[code]!.tag;
final inlined = tag == _Tag.inlinedSubroutine;
- if (children != null) {
- for (final child in children.values) {
- final callInfo = child.callInfo(unit, lineNumberProgram, address);
- if (callInfo == null) continue;
+ for (final child in children.values) {
+ final callInfo = child.callInfo(unit, lineNumberProgram, address);
+ if (callInfo == null) continue;
- if (tag == _Tag.compileUnit) return callInfo;
+ if (tag == _Tag.compileUnit) return callInfo;
- return callInfo
- ..add(DartCallInfo(
- function: unit.nameOfOrigin(abstractOrigin),
- inlined: inlined,
- filename: callFilename(child.callFileIndex),
- line: child.callLine,
- column: child.callColumn));
- }
+ return callInfo
+ ..add(DartCallInfo(
+ function: unit.nameOfOrigin(abstractOrigin ?? -1),
+ inlined: inlined,
+ filename: callFilename(child.callFileIndex ?? -1),
+ line: child.callLine ?? 0,
+ column: child.callColumn ?? 0));
}
if (tag == _Tag.compileUnit) return null;
- final filename = lineNumberProgram.filename(address);
- final line = lineNumberProgram.lineNumber(address);
- final column = lineNumberProgram.column(address);
+ final filename = lineNumberProgram.filename(address)!;
+ final line = lineNumberProgram.lineNumber(address)!;
+ final column = lineNumberProgram.column(address)!;
return [
DartCallInfo(
- function: unit.nameOfOrigin(abstractOrigin),
+ function: unit.nameOfOrigin(abstractOrigin ?? -1),
inlined: inlined,
filename: filename,
line: line,
@@ -359,21 +360,21 @@
}
void writeToStringBuffer(StringBuffer buffer,
- {CompilationUnit unit, String indent = ''}) {
+ {CompilationUnit? unit, String indent = ''}) {
buffer
..write(indent)
..write('Abbreviation code: ')
..write(code)
..writeln('):');
- for (final attribute in attributes.keys) {
+ attributes.forEach((attribute, value) {
buffer
..write(indent)
..write(' ')
- ..write(_attributeNameStrings[attribute.name])
+ ..write(_attributeNameStrings[attribute.name]!)
..write(' => ')
- ..writeln(attribute.valueToString(attributes[attribute], unit));
- }
- if (children != null) {
+ ..writeln(attribute.valueToString(value, unit));
+ });
+ if (children.isNotEmpty) {
buffer
..write(indent)
..write('Children (')
@@ -413,7 +414,7 @@
CompilationUnitHeader._(this.size, this.version, this.abbreviationsOffset,
this.addressSize, this.abbreviations);
- static CompilationUnitHeader fromReader(
+ static CompilationUnitHeader? fromReader(
Reader reader, Map<int, _AbbreviationsTable> abbreviationsTables) {
final size = _initialLengthValue(reader);
// An empty unit is an ending marker.
@@ -423,13 +424,14 @@
throw FormatException("Expected DWARF version 2, got $version");
}
final abbreviationsOffset = reader.readBytes(4);
- if (!abbreviationsTables.containsKey(abbreviationsOffset)) {
+ final abbreviationsTable = abbreviationsTables[abbreviationsOffset];
+ if (abbreviationsTable == null) {
throw FormatException("No abbreviation table found for offset "
"0x${paddedHex(abbreviationsOffset, 4)}");
}
final addressSize = reader.readByte();
- return CompilationUnitHeader._(size, version, abbreviationsOffset,
- addressSize, abbreviationsTables[abbreviationsOffset]);
+ return CompilationUnitHeader._(
+ size, version, abbreviationsOffset, addressSize, abbreviationsTable);
}
void writeToStringBuffer(StringBuffer buffer) {
@@ -461,7 +463,7 @@
CompilationUnit._(this.header, this.referenceTable);
- static CompilationUnit fromReader(
+ static CompilationUnit? fromReader(
Reader reader, Map<int, _AbbreviationsTable> abbreviationsTables) {
final header =
CompilationUnitHeader.fromReader(reader, abbreviationsTables);
@@ -477,25 +479,21 @@
static void _addChildEntries(Map<int, DebugInformationEntry> table) {
final workList = Queue<MapEntry<int, DebugInformationEntry>>();
for (final die in table.values) {
- if (die.children != null) {
- workList.addAll(die.children.entries);
- }
+ workList.addAll(die.children.entries);
}
while (workList.isNotEmpty) {
final kv = workList.removeFirst();
final offset = kv.key;
final child = kv.value;
table[offset] = child;
- if (child.children != null) {
- workList.addAll(child.children.entries);
- }
+ workList.addAll(child.children.entries);
}
}
- Iterable<CallInfo> callInfo(LineNumberInfo lineNumberInfo, int address) {
+ Iterable<CallInfo>? callInfo(LineNumberInfo lineNumberInfo, int address) {
for (final die in referenceTable.values) {
- final lineNumberProgram =
- lineNumberInfo[die[_AttributeName.statementList]];
+ final lineNumberProgram = lineNumberInfo[die.sectionOffset ?? -1];
+ if (lineNumberProgram == null) continue;
final callInfo = die.callInfo(this, lineNumberProgram, address);
if (callInfo != null) return callInfo;
}
@@ -503,26 +501,24 @@
}
String nameOfOrigin(int offset) {
- if (!referenceTable.containsKey(offset)) {
+ final origin = referenceTable[offset];
+ if (origin == null) {
throw ArgumentError(
"${paddedHex(offset)} is not the offset of an abbreviated unit");
}
- final origin = referenceTable[offset];
- assert(origin.containsKey(_AttributeName.name));
return origin[_AttributeName.name] as String;
}
void writeToStringBuffer(StringBuffer buffer) {
header.writeToStringBuffer(buffer);
- for (final offset in referenceTable.keys) {
- final die = referenceTable[offset];
+ referenceTable.forEach((offset, die) {
buffer
..write('Debug information entry at offset 0x')
..write(paddedHex(offset))
..writeln(':');
die.writeToStringBuffer(buffer, unit: this);
buffer.writeln();
- }
+ });
}
@override
@@ -548,7 +544,7 @@
return DebugInfo._(units);
}
- Iterable<CallInfo> callInfo(LineNumberInfo lineNumberInfo, int address) {
+ Iterable<CallInfo>? callInfo(LineNumberInfo lineNumberInfo, int address) {
for (final unit in units) {
final callInfo = unit.callInfo(lineNumberInfo, address);
if (callInfo != null) return callInfo;
@@ -578,7 +574,7 @@
FileEntry._(this.name, this.directoryIndex, this.lastModified, this.size);
- static FileEntry fromReader(Reader reader) {
+ static FileEntry? fromReader(Reader reader) {
final name = reader.readNullTerminatedString();
// An empty null-terminated string marks the table end.
if (name == "") return null;
@@ -611,7 +607,7 @@
}
bool containsKey(int index) => _files.containsKey(index);
- FileEntry operator [](int index) => _files[index];
+ FileEntry? operator [](int index) => _files[index];
void writeToStringBuffer(StringBuffer buffer) {
if (_files.isEmpty) {
@@ -654,17 +650,17 @@
..writeln(nameHeader);
for (final index in _files.keys) {
- buffer..write(" ")..write(indexStrings[index].padRight(maxIndexLength));
+ buffer..write(" ")..write(indexStrings[index]!.padRight(maxIndexLength));
buffer
..write(" ")
- ..write(dirIndexStrings[index].padRight(maxDirIndexLength));
+ ..write(dirIndexStrings[index]!.padRight(maxDirIndexLength));
buffer
..write(" ")
- ..write(modifiedStrings[index].padRight(maxModifiedLength));
- buffer..write(" ")..write(sizeStrings[index].padRight(maxSizeLength));
+ ..write(modifiedStrings[index]!.padRight(maxModifiedLength));
+ buffer..write(" ")..write(sizeStrings[index]!.padRight(maxSizeLength));
buffer
..write(" ")
- ..writeln(_files[index].name);
+ ..writeln(_files[index]!.name);
}
}
@@ -679,13 +675,13 @@
class LineNumberState {
final defaultIsStatement;
- int address;
- int fileIndex;
- int line;
- int column;
- bool isStatement;
- bool basicBlock;
- bool endSequence;
+ late int address;
+ late int fileIndex;
+ late int line;
+ late int column;
+ late bool isStatement;
+ late bool basicBlock;
+ late bool endSequence;
LineNumberState(this.defaultIsStatement) {
reset();
@@ -749,7 +745,7 @@
this.includeDirectories,
this.filesInfo);
- static LineNumberProgramHeader fromReader(Reader reader) {
+ static LineNumberProgramHeader? fromReader(Reader reader) {
final size = _initialLengthValue(reader);
if (size == 0) return null;
final version = reader.readBytes(2);
@@ -861,7 +857,7 @@
LineNumberProgram._(this.header, this.calculatedMatrix) : cachedLookups = {};
- static LineNumberProgram fromReader(Reader reader) {
+ static LineNumberProgram? fromReader(Reader reader) {
final header = LineNumberProgramHeader.fromReader(reader);
if (header == null) return null;
final calculatedMatrix = _readOpcodes(reader, header).toList();
@@ -955,14 +951,14 @@
address < calculatedMatrix.last.address;
}
- LineNumberState operator [](int address) {
+ LineNumberState? operator [](int address) {
if (cachedLookups.containsKey(address)) return cachedLookups[address];
if (!containsKey(address)) return null;
// Since the addresses are generated in increasing order, we can do a
// binary search to find the right state.
- assert(calculatedMatrix != null && calculatedMatrix.isNotEmpty);
+ assert(calculatedMatrix.isNotEmpty);
var minIndex = 0;
var maxIndex = calculatedMatrix.length - 1;
while (true) {
@@ -983,12 +979,12 @@
}
}
- String filename(int address) =>
- header.filesInfo[this[address]?.fileIndex]?.name;
+ String? filename(int address) =>
+ header.filesInfo[this[address]?.fileIndex ?? -1]?.name;
- int lineNumber(int address) => this[address]?.line;
+ int? lineNumber(int address) => this[address]?.line;
- int column(int address) => this[address]?.column;
+ int? column(int address) => this[address]?.column;
void writeToStringBuffer(StringBuffer buffer) {
header.writeToStringBuffer(buffer);
@@ -1019,15 +1015,15 @@
}
bool containsKey(int address) => programs.containsKey(address);
- LineNumberProgram operator [](int address) => programs[address];
+ LineNumberProgram? operator [](int address) => programs[address];
void writeToStringBuffer(StringBuffer buffer) {
- for (final offset in programs.keys) {
+ programs.forEach((offset, program) {
buffer
..write('Line number program @ 0x')
..writeln(paddedHex(offset));
- programs[offset].writeToStringBuffer(buffer);
- }
+ program.writeToStringBuffer(buffer);
+ });
}
String toString() {
@@ -1068,10 +1064,10 @@
DartCallInfo(
{this.inlined = false,
- this.function,
- this.filename,
- this.line,
- this.column});
+ required this.function,
+ required this.filename,
+ required this.line,
+ required this.column});
@override
bool get isInternal => false;
@@ -1122,7 +1118,7 @@
final String name;
final int offset;
- StubCallInfo({this.name, this.offset});
+ StubCallInfo({required this.name, required this.offset});
@override
int get hashCode => _hashFinish(
@@ -1156,9 +1152,11 @@
/// The call information found for this [PCOffset] in [dwarf].
///
+ /// Returns null if the PCOffset is invalid for the given DWARF information.
+ ///
/// If [includeInternalFrames] is false, then only information corresponding
/// to user or library code is returned.
- Iterable<CallInfo> callInfoFrom(Dwarf dwarf,
+ Iterable<CallInfo>? callInfoFrom(Dwarf dwarf,
{bool includeInternalFrames = false}) =>
dwarf.callInfoFor(dwarf.virtualAddressOf(this),
includeInternalFrames: includeInternalFrames);
@@ -1180,7 +1178,7 @@
/// The DWARF debugging information for a Dart snapshot.
class Dwarf {
final Elf _elf;
- final Map<int, _AbbreviationsTable> _abbreviationTables;
+ final Map<int, _AbbreviationsTable> _abbreviationsTables;
final DebugInfo _debugInfo;
final LineNumberInfo _lineNumberInfo;
@@ -1192,13 +1190,13 @@
/// DWARF information.
final int isolateStartAddress;
- Dwarf._(this._elf, this._abbreviationTables, this._debugInfo,
+ Dwarf._(this._elf, this._abbreviationsTables, this._debugInfo,
this._lineNumberInfo, this.vmStartAddress, this.isolateStartAddress);
/// Attempts to load the DWARF debugging information from the reader.
///
/// Returns a [Dwarf] object if the load succeeds, otherwise returns null.
- static Dwarf fromReader(Reader reader) {
+ static Dwarf? fromReader(Reader reader) {
// Currently, the only DWARF-containing format we recognize is ELF.
final elf = Elf.fromReader(reader);
if (elf == null) return null;
@@ -1208,18 +1206,19 @@
/// Attempts to load the DWARF debugging information from the given bytes.
///
/// Returns a [Dwarf] object if the load succeeds, otherwise returns null.
- static Dwarf fromBytes(Uint8List bytes) =>
+ static Dwarf? fromBytes(Uint8List bytes) =>
Dwarf.fromReader(Reader.fromTypedData(bytes));
/// Attempts to load the DWARF debugging information from the file at [path].
///
/// Returns a [Dwarf] object if the load succeeds, otherwise returns null.
- static Dwarf fromFile(String path) => Dwarf.fromReader(Reader.fromFile(path));
+ static Dwarf? fromFile(String path) =>
+ Dwarf.fromReader(Reader.fromFile(path));
static Dwarf _loadSectionsFromElf(Reader reader, Elf elf) {
final abbrevSection = elf.namedSections(".debug_abbrev").single;
final abbrevReader = abbrevSection.refocusedCopy(reader);
- final abbreviationTables = Map.fromEntries(
+ final abbreviationsTables = Map.fromEntries(
abbrevReader.readRepeatedWithOffsets(_AbbreviationsTable.fromReader));
final lineNumberSection = elf.namedSections(".debug_line").single;
@@ -1228,7 +1227,7 @@
final infoSection = elf.namedSections(".debug_info").single;
final debugInfo = DebugInfo.fromReader(
- infoSection.refocusedCopy(reader), abbreviationTables);
+ infoSection.refocusedCopy(reader), abbreviationsTables);
final vmStartSymbol = elf.dynamicSymbolFor(constants.vmSymbolName);
if (vmStartSymbol == null) {
@@ -1245,29 +1244,33 @@
}
final isolateStartAddress = isolateStartSymbol.value;
- return Dwarf._(elf, abbreviationTables, debugInfo, lineNumberInfo,
+ return Dwarf._(elf, abbreviationsTables, debugInfo, lineNumberInfo,
vmStartAddress, isolateStartAddress);
}
/// The build ID for the debugging information.
///
/// Returns null if there is no build ID information recorded.
- String get buildId {
+ String? get buildId {
final sections = _elf.namedSections(constants.buildIdSectionName);
if (sections.isEmpty) return null;
- final Note note = sections.single;
+ final note = sections.single as Note;
if (note.type != constants.buildIdNoteType) return null;
if (note.name != constants.buildIdNoteName) return null;
- return note.description.map((i) => i.toRadixString(16)).join();
+ return note.description
+ .map((i) => i.toRadixString(16).padLeft(2, '0'))
+ .join();
}
/// The call information for the given virtual address. There may be
/// multiple [CallInfo] objects returned for a single virtual address when
/// code has been inlined.
///
+ /// Returns null if the given address is invalid for the DWARF information.
+ ///
/// If [includeInternalFrames] is false, then only information corresponding
/// to user or library code is returned.
- Iterable<CallInfo> callInfoFor(int address,
+ Iterable<CallInfo>? callInfoFor(int address,
{bool includeInternalFrames = false}) {
var calls = _debugInfo.callInfo(_lineNumberInfo, address);
if (calls == null) {
@@ -1304,10 +1307,10 @@
..writeln(' Abbreviation tables')
..writeln('----------------------------------------')
..writeln();
- for (final offset in _abbreviationTables.keys) {
+ _abbreviationsTables.forEach((offset, table) {
buffer..write('(Offset ')..write(paddedHex(offset, 4))..write(') ');
- _abbreviationTables[offset].writeToStringBuffer(buffer);
- }
+ table.writeToStringBuffer(buffer);
+ });
buffer
..writeln('----------------------------------------')
..writeln(' Debug information')
diff --git a/pkg/native_stack_traces/lib/src/elf.dart b/pkg/native_stack_traces/lib/src/elf.dart
index b0c7c54..e92fecd 100644
--- a/pkg/native_stack_traces/lib/src/elf.dart
+++ b/pkg/native_stack_traces/lib/src/elf.dart
@@ -95,7 +95,7 @@
this.sectionHeaderEntrySize,
this.sectionHeaderStringsIndex);
- static ElfHeader fromReader(Reader reader) {
+ static ElfHeader? fromReader(Reader reader) {
final fileSize = reader.length;
for (final sigByte in _ELFMAG.codeUnits) {
@@ -275,10 +275,11 @@
this.paddr, this.filesz, this.memsz, this.align, this.wordSize);
static ProgramHeaderEntry fromReader(Reader reader) {
- assert(reader.wordSize == 4 || reader.wordSize == 8);
+ int wordSize = reader.wordSize;
+ assert(wordSize == 4 || wordSize == 8);
final type = _readElfWord(reader);
- int flags;
- if (reader.wordSize == 8) {
+ late int flags;
+ if (wordSize == 8) {
flags = _readElfWord(reader);
}
final offset = _readElfOffset(reader);
@@ -286,12 +287,12 @@
final paddr = _readElfAddress(reader);
final filesz = _readElfNative(reader);
final memsz = _readElfNative(reader);
- if (reader.wordSize == 4) {
+ if (wordSize == 4) {
flags = _readElfWord(reader);
}
final align = _readElfNative(reader);
- return ProgramHeaderEntry._(type, flags, offset, vaddr, paddr, filesz,
- memsz, align, reader.wordSize);
+ return ProgramHeaderEntry._(
+ type, flags, offset, vaddr, paddr, filesz, memsz, align, wordSize);
}
static const _typeStrings = <int, String>{
@@ -301,12 +302,8 @@
_PT_PHDR: "PT_PHDR",
};
- static String _typeToString(int type) {
- if (_typeStrings.containsKey(type)) {
- return _typeStrings[type];
- }
- return "unknown (${paddedHex(type, 4)})";
- }
+ static String _typeToString(int type) =>
+ _typeStrings[type] ?? "unknown (${paddedHex(type, 4)})";
void writeToStringBuffer(StringBuffer buffer) {
buffer
@@ -384,7 +381,7 @@
final int addrAlign;
final int entrySize;
final int wordSize;
- String _cachedName;
+ late String name;
SectionHeaderEntry._(
this.nameIndex,
@@ -426,11 +423,9 @@
static const _SHT_DYNSYM = 11;
void setName(StringTable nameTable) {
- _cachedName = nameTable[nameIndex];
+ name = nameTable[nameIndex]!;
}
- String get name => _cachedName != null ? _cachedName : '<${nameIndex}>';
-
static const _typeStrings = <int, String>{
_SHT_NULL: "SHT_NULL",
_SHT_PROGBITS: "SHT_PROGBITS",
@@ -443,25 +438,17 @@
_SHT_DYNSYM: "SHT_DYNSYM",
};
- static String _typeToString(int type) {
- if (_typeStrings.containsKey(type)) {
- return _typeStrings[type];
- }
- return "unknown (${paddedHex(type, 4)})";
- }
+ static String _typeToString(int type) =>
+ _typeStrings[type] ?? "unknown (${paddedHex(type, 4)})";
void writeToStringBuffer(StringBuffer buffer) {
buffer.write('Name: ');
- if (_cachedName != null) {
- buffer
- ..write('"')
- ..write(name)
- ..write('" (@ ')
- ..write(nameIndex)
- ..writeln(')');
- } else {
- buffer.writeln(name);
- }
+ buffer
+ ..write('"')
+ ..write(name)
+ ..write('" (@ ')
+ ..write(nameIndex)
+ ..writeln(')');
buffer
..write('Type: ')
..writeln(_typeToString(type))
@@ -629,7 +616,7 @@
/// A map from table offsets to strings, used to store names of ELF objects.
class StringTable extends Section {
- final _entries;
+ final Map<int, String> _entries;
StringTable._(entry, this._entries) : super._(entry);
@@ -640,7 +627,7 @@
return StringTable._(entry, entries);
}
- String operator [](int index) => _entries[index];
+ String? operator [](int index) => _entries[index];
bool containsKey(int index) => _entries.containsKey(index);
@override
@@ -685,40 +672,40 @@
final int sectionIndex;
final int value;
final int size;
-
final int _wordSize;
-
- String name;
+ late String name;
Symbol._(this.nameIndex, this.info, this.other, this.sectionIndex, this.value,
this.size, this._wordSize);
static Symbol fromReader(Reader reader) {
+ final wordSize = reader.wordSize;
final nameIndex = _readElfWord(reader);
- int info;
- int other;
- int sectionIndex;
- if (reader.wordSize == 8) {
+ late int info;
+ late int other;
+ late int sectionIndex;
+ if (wordSize == 8) {
info = reader.readByte();
other = reader.readByte();
sectionIndex = _readElfSection(reader);
}
final value = _readElfAddress(reader);
final size = _readElfNative(reader);
- if (reader.wordSize == 4) {
+ if (wordSize == 4) {
info = reader.readByte();
other = reader.readByte();
sectionIndex = _readElfSection(reader);
}
return Symbol._(
- nameIndex, info, other, sectionIndex, value, size, reader.wordSize);
+ nameIndex, info, other, sectionIndex, value, size, wordSize);
}
void _cacheNameFromStringTable(StringTable table) {
- if (!table.containsKey(nameIndex)) {
+ final nameFromTable = table[nameIndex];
+ if (nameFromTable == null) {
throw FormatException("Index $nameIndex not found in string table");
}
- name = table[nameIndex];
+ name = nameFromTable;
}
SymbolBinding get bind => SymbolBinding.values[info >> 4];
@@ -726,11 +713,7 @@
SymbolVisibility get visibility => SymbolVisibility.values[other & 0x03];
void writeToStringBuffer(StringBuffer buffer) {
- if (name != null) {
- buffer..write('"')..write(name)..write('" =>');
- } else {
- buffer..write('<')..write(nameIndex)..write('> =>');
- }
+ buffer..write('"')..write(name)..write('" =>');
switch (bind) {
case SymbolBinding.STB_GLOBAL:
buffer..write(' a global');
@@ -793,8 +776,8 @@
}
Iterable<String> get keys => _nameCache.keys;
- Iterable<Symbol> get values => _nameCache.values;
- Symbol operator [](String name) => _nameCache[name];
+ Iterable<Symbol> get values => _entries;
+ Symbol? operator [](String name) => _nameCache[name];
bool containsKey(String name) => _nameCache.containsKey(name);
@override
@@ -825,21 +808,23 @@
/// Creates an [Elf] from [bytes].
///
/// Returns null if the file does not start with the ELF magic number.
- static Elf fromBuffer(Uint8List bytes) =>
+ static Elf? fromBuffer(Uint8List bytes) =>
Elf.fromReader(Reader.fromTypedData(bytes));
/// Creates an [Elf] from the file at [path].
///
/// Returns null if the file does not start with the ELF magic number.
- static Elf fromFile(String path) => Elf.fromReader(Reader.fromFile(path));
+ static Elf? fromFile(String path) => Elf.fromReader(Reader.fromFile(path));
- Iterable<Section> namedSections(String name) => _sectionsByName[name];
+ Iterable<Section> namedSections(String name) =>
+ _sectionsByName[name] ?? <Section>[];
/// Lookup of a dynamic symbol by name.
///
/// Returns -1 if there is no dynamic symbol that matches [name].
- Symbol dynamicSymbolFor(String name) {
- for (final SymbolTable dynsym in namedSections(".dynsym")) {
+ Symbol? dynamicSymbolFor(String name) {
+ for (final section in namedSections(".dynsym")) {
+ final dynsym = section as SymbolTable;
if (dynsym.containsKey(name)) return dynsym[name];
}
return null;
@@ -847,8 +832,9 @@
/// Reverse lookup of the static symbol that contains the given virtual
/// address. Returns null if no static symbol matching the address is found.
- Symbol staticSymbolAt(int address) {
- for (final SymbolTable table in namedSections('.symtab')) {
+ Symbol? staticSymbolAt(int address) {
+ for (final section in namedSections('.symtab')) {
+ final table = section as SymbolTable;
for (final symbol in table.values) {
final start = symbol.value;
final end = start + symbol.size;
@@ -865,7 +851,7 @@
/// of the reader will be unchanged.
///
/// Returns null if the file does not start with the ELF magic number.
- static Elf fromReader(Reader elfReader) {
+ static Elf? fromReader(Reader elfReader) {
// ELF files contain absolute offsets from the start of the file, so
// make sure we have a reader that a) makes no assumptions about the
// endianness or word size, since we'll read those in the header and b)
@@ -887,24 +873,47 @@
}
// Now set up the by-name section table and cache the names in the section
// header entries.
- final StringTable sectionHeaderStringTable =
- sections[sectionHeader.entries[header.sectionHeaderStringsIndex]];
+ if (header.sectionHeaderStringsIndex < 0 ||
+ header.sectionHeaderStringsIndex >= sectionHeader.entries.length) {
+ throw FormatException("Section header string table index invalid");
+ }
+ final sectionHeaderStringTableEntry =
+ sectionHeader.entries[header.sectionHeaderStringsIndex];
+ final sectionHeaderStringTable =
+ sections[sectionHeaderStringTableEntry] as StringTable?;
+ if (sectionHeaderStringTable == null) {
+ throw FormatException(
+ "No section for entry ${sectionHeaderStringTableEntry}");
+ }
final sectionsByName = <String, Set<Section>>{};
for (final entry in sectionHeader.entries) {
+ final section = sections[entry];
+ if (section == null) {
+ throw FormatException("No section found for entry ${entry}");
+ }
entry.setName(sectionHeaderStringTable);
- sectionsByName.putIfAbsent(entry.name, () => {}).add(sections[entry]);
+ sectionsByName.putIfAbsent(entry.name, () => {}).add(section);
}
void _cacheSymbolNames(String stringTableTag, String symbolTableTag) {
- final stringTables = Map.fromEntries(sectionsByName[stringTableTag]
- .map((s) => MapEntry(s.headerEntry, s)));
- for (final SymbolTable symbolTable in sectionsByName[symbolTableTag]) {
+ final stringTables = sectionsByName[stringTableTag]?.cast<StringTable>();
+ if (stringTables == null) {
+ return;
+ }
+ final stringTableMap =
+ Map.fromEntries(stringTables.map((s) => MapEntry(s.headerEntry, s)));
+ final symbolTables = sectionsByName[symbolTableTag]?.cast<SymbolTable>();
+ if (symbolTables == null) {
+ return;
+ }
+ for (final symbolTable in symbolTables) {
final link = symbolTable.headerEntry.link;
final entry = sectionHeader.entries[link];
- if (!stringTables.containsKey(entry)) {
+ final stringTable = stringTableMap[entry];
+ if (stringTable == null) {
throw FormatException(
"String table not found at section header entry ${link}");
}
- symbolTable._cacheNames(stringTables[entry]);
+ symbolTable._cacheNames(stringTable);
}
}
@@ -948,7 +957,7 @@
..writeln('-----------------------------------------------------')
..writeln();
for (final entry in _sectionHeader.entries) {
- _sections[entry].writeToStringBuffer(buffer);
+ _sections[entry]!.writeToStringBuffer(buffer);
buffer.writeln();
}
}
diff --git a/pkg/native_stack_traces/lib/src/reader.dart b/pkg/native_stack_traces/lib/src/reader.dart
index 21f6297..9eb5be6 100644
--- a/pkg/native_stack_traces/lib/src/reader.dart
+++ b/pkg/native_stack_traces/lib/src/reader.dart
@@ -14,26 +14,35 @@
final ByteData bdata;
// These are mutable so we can update them, in case the endianness and
// wordSize are read using the reader (e.g., ELF files).
- Endian endian;
- int wordSize;
+ Endian? _endian;
+ int? _wordSize;
int _offset = 0;
+ Endian get endian => _endian as Endian;
+ void set endian(Endian value) => _endian = value;
+ int get wordSize => _wordSize as int;
+ void set wordSize(int value) => _wordSize = value;
+
/// Unless provided, [wordSize] and [endian] are initialized to values that
/// ensure no reads are made that depend on their value (e.g., readBytes).
- Reader.fromTypedData(TypedData data, {this.wordSize = -1, this.endian})
- : bdata =
+ Reader.fromTypedData(TypedData data, {int? wordSize, Endian? endian})
+ : _wordSize = wordSize,
+ _endian = endian,
+ bdata =
ByteData.view(data.buffer, data.offsetInBytes, data.lengthInBytes);
- Reader.fromFile(String path, {this.wordSize, this.endian})
- : bdata = ByteData.sublistView(File(path).readAsBytesSync());
+ Reader.fromFile(String path, {int? wordSize, Endian? endian})
+ : _wordSize = wordSize,
+ _endian = endian,
+ bdata = ByteData.sublistView(File(path).readAsBytesSync());
/// Returns a reader focused on a different portion of the underlying buffer.
Reader refocusedCopy(int pos, int size) {
assert(pos >= 0 && pos < bdata.buffer.lengthInBytes);
assert(size >= 0 && (pos + size) <= bdata.buffer.lengthInBytes);
return Reader.fromTypedData(ByteData.view(bdata.buffer, pos, size),
- wordSize: wordSize, endian: endian);
+ wordSize: _wordSize, endian: _endian);
}
int get start => bdata.offsetInBytes;
@@ -65,7 +74,6 @@
return signed
? bdata.getInt32(start, endian)
: bdata.getUint32(start, endian);
- break;
case 8:
return signed
? bdata.getInt64(start, endian)
@@ -116,7 +124,7 @@
/// Stops either when the reader is empty or when a null item is returned
/// from the callback.
Iterable<MapEntry<int, S>> readRepeatedWithOffsets<S>(
- S Function(Reader) callback,
+ S? Function(Reader) callback,
{bool absolute = false}) sync* {
final start = offset;
while (!done) {
@@ -127,7 +135,7 @@
}
}
- Iterable<S> readRepeated<S>(S Function(Reader) callback) =>
+ Iterable<S> readRepeated<S>(S? Function(Reader) callback) =>
readRepeatedWithOffsets(callback).map((kv) => kv.value);
void writeCurrentReaderPosition(StringBuffer buffer,
@@ -160,27 +168,27 @@
final buffer = StringBuffer();
buffer
..write("Word size: ")
- ..write(wordSize)
+ ..write(_wordSize)
..writeln();
buffer
..write("Endianness: ")
- ..write(endian)
+ ..write(_endian)
..writeln();
buffer
..write("Start: 0x")
- ..write(paddedHex(start, wordSize ?? 0))
+ ..write(paddedHex(start, _wordSize ?? 0))
..write(" (")
..write(start)
..writeln(")");
buffer
..write("Offset: 0x")
- ..write(paddedHex(offset, wordSize ?? 0))
+ ..write(paddedHex(offset, _wordSize ?? 0))
..write(" (")
..write(offset)
..writeln(")");
buffer
..write("Length: 0x")
- ..write(paddedHex(length, wordSize ?? 0))
+ ..write(paddedHex(length, _wordSize ?? 0))
..write(" (")
..write(length)
..writeln(")");
diff --git a/pkg/native_stack_traces/pubspec.yaml b/pkg/native_stack_traces/pubspec.yaml
index cc0d214..f831df6 100644
--- a/pkg/native_stack_traces/pubspec.yaml
+++ b/pkg/native_stack_traces/pubspec.yaml
@@ -1,18 +1,19 @@
name: native_stack_traces
description: Utilities for working with non-symbolic stack traces.
-version: 0.3.8
+version: 0.4.0-nullsafety
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/native_stack_traces
environment:
- sdk: '>=2.8.0 <3.0.0'
+ # This must remain a tight constraint until nnbd is stable
+ sdk: '>=2.10.0-0 <2.10.0'
executables:
decode:
dependencies:
- args: ^1.5.2
- path: ^1.6.4
+ args: ^1.6.0
+ path: ^1.8.0-nullsafety
dev_dependencies:
- pedantic: ^1.8.0
+ pedantic: ^1.9.2
diff --git a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
index 13e52db..4c776c8 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
@@ -59,13 +59,6 @@
}
@override
- bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
- return variable is LocalVariableElement &&
- variable.hasImplicitType &&
- !variable.hasInitializer;
- }
-
- @override
bool isNever(DecoratedType type) {
return false;
}
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 4920fce..8c74da4 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -54,6 +54,10 @@
bool get supportsLateFields => !flags.forceLateLoweringForTesting;
@override
+ bool get supportsLateLoweringSentinel =>
+ flags.forceLateLoweringSentinelForTesting;
+
+ @override
bool get useStaticFieldLowering => flags.forceStaticFieldLoweringForTesting;
@override
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 0d06590..b049853 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 5.2.0
+- Added support for `dart:io` extensions version 1.3.
+- Added combination getter/setter `httpEnableTimelineLogging`.
+- Deprecated `getHttpEnableTimelineLogging` and `setHttpEnableTimelineLogging`.
+
## 5.1.0
- Added support for `dart:io` extensions version 1.2.
- Added `getOpenFiles`, `getOpenFileById`, `getSpawnedProcesses`, and `getSpawnedProcessById` RPCs.
diff --git a/pkg/vm_service/lib/src/dart_io_extensions.dart b/pkg/vm_service/lib/src/dart_io_extensions.dart
index ddecfc5..ce777d6 100644
--- a/pkg/vm_service/lib/src/dart_io_extensions.dart
+++ b/pkg/vm_service/lib/src/dart_io_extensions.dart
@@ -43,6 +43,7 @@
///
/// Warning: The returned [Future] will not complete if the target isolate is paused
/// and will only complete when the isolate is resumed.
+ @Deprecated('Use httpEnableTimelineLogging instead.')
Future<HttpTimelineLoggingState> getHttpEnableTimelineLogging(
String isolateId) =>
_callHelper('ext.dart.io.getHttpEnableTimelineLogging', isolateId);
@@ -51,11 +52,18 @@
///
/// Warning: The returned [Future] will not complete if the target isolate is paused
/// and will only complete when the isolate is resumed.
+ @Deprecated('Use httpEnableTimelineLogging instead.')
Future<Success> setHttpEnableTimelineLogging(String isolateId, bool enable) =>
_callHelper('ext.dart.io.setHttpEnableTimelineLogging', isolateId, args: {
'enable': enable,
});
+ Future<HttpTimelineLoggingState> httpEnableTimelineLogging(String isolateId,
+ [bool enable]) =>
+ _callHelper('ext.dart.io.httpEnableTimelineLogging', isolateId, args: {
+ if (enable != null) 'enable': enable,
+ });
+
/// The `getOpenFiles` RPC is used to retrieve the list of files currently
/// opened files by `dart:io` from a given isolate.
Future<OpenFileList> getOpenFiles(String isolateId) => _callHelper(
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index dd8502a..c2280d1 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 5.1.0+1
+version: 5.2.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
index 0b849c6..b236cc4 100644
--- a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
+++ b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
+
import 'package:vm_service/vm_service.dart';
import 'package:vm_service/src/dart_io_extensions.dart';
import 'package:test/test.dart';
@@ -12,8 +14,34 @@
'ext.dart.io.setHttpEnableTimelineLogging';
const String kGetHttpEnableTimelineLogging =
'ext.dart.io.getHttpEnableTimelineLogging';
+const String kHttpEnableTimelineLogging =
+ 'ext.dart.io.httpEnableTimelineLogging';
Future<void> setup() async {}
+Future<void> waitForStreamEvent(
+ VmService service, IsolateRef isolateRef, bool state,
+ {bool useSetter = true}) async {
+ final completer = Completer<void>();
+ final isolateId = isolateRef.id;
+ StreamSubscription sub;
+ sub = service.onExtensionEvent.listen((event) {
+ expect(event.extensionKind, 'HttpTimelineLoggingStateChange');
+ expect(event.extensionData.data['isolateId'], isolateRef.id);
+ expect(event.extensionData.data['enabled'], state);
+ sub.cancel();
+ completer.complete();
+ });
+ await service.streamListen(EventStreams.kExtension);
+
+ if (useSetter) {
+ await service.setHttpEnableTimelineLogging(isolateId, state);
+ } else {
+ await service.httpEnableTimelineLogging(isolateId, state);
+ }
+ await completer.future;
+ await service.streamCancel(EventStreams.kExtension);
+}
+
var tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
@@ -23,22 +51,34 @@
isolate.extensionRPCs.contains(kGetHttpEnableTimelineLogging), isTrue);
expect(
isolate.extensionRPCs.contains(kSetHttpEnableTimelineLogging), isTrue);
+ expect(isolate.extensionRPCs.contains(kHttpEnableTimelineLogging), isTrue);
},
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id;
dynamic response = await service.getHttpEnableTimelineLogging(isolateId);
expect(response.enabled, false);
- await service.setHttpEnableTimelineLogging(isolateId, true);
-
+ await waitForStreamEvent(service, isolateRef, true);
response = await service.getHttpEnableTimelineLogging(isolateId);
expect(response.enabled, true);
- await service.setHttpEnableTimelineLogging(isolateId, false);
-
+ await waitForStreamEvent(service, isolateRef, false);
response = await service.getHttpEnableTimelineLogging(isolateId);
expect(response.enabled, false);
},
+ (VmService service, IsolateRef isolateRef) async {
+ final isolateId = isolateRef.id;
+ dynamic response = await service.httpEnableTimelineLogging(isolateId, null);
+ expect(response.enabled, false);
+
+ await waitForStreamEvent(service, isolateRef, true, useSetter: false);
+ response = await service.httpEnableTimelineLogging(isolateId, null);
+ expect(response.enabled, true);
+
+ await waitForStreamEvent(service, isolateRef, false, useSetter: false);
+ response = await service.httpEnableTimelineLogging(isolateId);
+ expect(response.enabled, false);
+ },
];
main([args = const <String>[]]) async =>
diff --git a/runtime/bin/elf_loader.cc b/runtime/bin/elf_loader.cc
index c67f391..22c2cbc 100644
--- a/runtime/bin/elf_loader.cc
+++ b/runtime/bin/elf_loader.cc
@@ -476,7 +476,6 @@
".bss does not have enough space.");
vm_bss_ = reinterpret_cast<uword*>(base_->start() + header.memory_offset);
isolate_bss_ = vm_bss_ + BSS::kVmEntryCount;
- // We set applicable BSS entries in ResolveSymbols().
}
}
@@ -504,22 +503,10 @@
output = vm_data;
} else if (strcmp(name, kVmSnapshotInstructionsAsmSymbol) == 0) {
output = vm_instrs;
- if (output != nullptr) {
- // Store the value of the symbol in the VM BSS, as it contains the
- // address of the VM instructions section relative to the DSO base.
- BSS::InitializeBSSEntry(BSS::Relocation::InstructionsRelocatedAddress,
- sym.value, vm_bss_);
- }
} else if (strcmp(name, kIsolateSnapshotDataAsmSymbol) == 0) {
output = isolate_data;
} else if (strcmp(name, kIsolateSnapshotInstructionsAsmSymbol) == 0) {
output = isolate_instrs;
- if (output != nullptr) {
- // Store the value of the symbol in the isolate BSS, as it contains the
- // address of the isolate instructions section relative to the DSO base.
- BSS::InitializeBSSEntry(BSS::Relocation::InstructionsRelocatedAddress,
- sym.value, isolate_bss_);
- }
}
if (output != nullptr) {
diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart
index 4a56ae7..0b14b5c 100644
--- a/runtime/tests/vm/dart/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart/causal_stacks/utils.dart
@@ -187,7 +187,7 @@
final decodeTrace = frames.first.startsWith('Warning:');
if (decodeTrace) {
Expect.isNotNull(debugInfoFilename);
- final dwarf = Dwarf.fromFile(debugInfoFilename!);
+ final dwarf = Dwarf.fromFile(debugInfoFilename!)!;
frames = await Stream.fromIterable(original)
.transform(DwarfStackTraceDecoder(dwarf))
.where(_lineRE.hasMatch)
diff --git a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
index 07a40c0..5d9fe49 100644
--- a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
@@ -112,8 +112,16 @@
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
- final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo);
- assert(dwarf != null);
+ final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo)!;
+
+ // Check that build IDs match for traces.
+ final buildId1 = buildId(dwarfTrace1);
+ Expect.isFalse(buildId1.isEmpty);
+ Expect.equals(dwarf.buildId!, buildId1);
+ final buildId2 = buildId(dwarfTrace2);
+ Expect.isFalse(buildId2.isEmpty);
+ Expect.equals(dwarf.buildId!, buildId2);
+
final translatedDwarfTrace1 = await Stream.fromIterable(dwarfTrace1)
.transform(DwarfStackTraceDecoder(dwarf))
.toList();
@@ -178,6 +186,17 @@
});
}
+final _buildIdRE = RegExp(r"build_id: '([a-f\d]+)'");
+String buildId(Iterable<String> lines) {
+ for (final line in lines) {
+ final match = _buildIdRE.firstMatch(line);
+ if (match != null) {
+ return match.group(1)!;
+ }
+ }
+ return '';
+}
+
final _symbolicFrameRE = RegExp(r'^#\d+\s+');
Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
diff --git a/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart b/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart
index 5ed1c3a..cfc8f16 100644
--- a/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart
+++ b/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart
@@ -114,8 +114,8 @@
print("Original stack trace:");
strippedTrace.forEach(print);
- final debugDwarf = Dwarf.fromFile(scriptDebuggingInfo);
- final wholeDwarf = Dwarf.fromFile(scriptWholeSnapshot);
+ final debugDwarf = Dwarf.fromFile(scriptDebuggingInfo)!;
+ final wholeDwarf = Dwarf.fromFile(scriptWholeSnapshot)!;
final fromDebug = await Stream.fromIterable(strippedTrace)
.transform(DwarfStackTraceDecoder(debugDwarf))
diff --git a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
index 40aa94a..7f3557e 100644
--- a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
@@ -113,7 +113,17 @@
// Check that translating the DWARF stack trace (without internal frames)
// matches the symbolic stack trace.
final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo);
- assert(dwarf != null);
+ Expect.isNotNull(dwarf);
+
+ // Check that build IDs match for traces.
+ Expect.isNotNull(dwarf.buildId);
+ final buildId1 = buildId(dwarfTrace1);
+ Expect.isFalse(buildId1.isEmpty);
+ Expect.equals(dwarf.buildId, buildId1);
+ final buildId2 = buildId(dwarfTrace2);
+ Expect.isFalse(buildId2.isEmpty);
+ Expect.equals(dwarf.buildId, buildId2);
+
final translatedDwarfTrace1 = await Stream.fromIterable(dwarfTrace1)
.transform(DwarfStackTraceDecoder(dwarf))
.toList();
@@ -178,6 +188,17 @@
});
}
+final _buildIdRE = RegExp(r"build_id: '([a-f\d]+)'");
+String buildId(Iterable<String> lines) {
+ for (final line in lines) {
+ final match = _buildIdRE.firstMatch(line);
+ if (match != null) {
+ return match.group(1);
+ }
+ }
+ return '';
+}
+
final _symbolicFrameRE = RegExp(r'^#\d+\s+');
Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 1d00e78..2215c7d 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -17,6 +17,7 @@
#include "vm/clustered_snapshot.h"
#include "vm/dart_api_impl.h"
+#include "vm/datastream.h"
#include "vm/stack_frame.h"
#include "vm/timer.h"
@@ -500,12 +501,6 @@
benchmark->set_score(elapsed_time);
}
-static uint8_t* malloc_allocator(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
-}
-
BENCHMARK_SIZE(CoreSnapshotSize) {
const char* kScriptChars =
"import 'dart:async';\n"
@@ -519,8 +514,6 @@
"\n";
// Start an Isolate, load a script and create a full snapshot.
- uint8_t* vm_snapshot_data_buffer;
- uint8_t* isolate_snapshot_data_buffer;
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
@@ -532,17 +525,16 @@
Api::CheckAndFinalizePendingClasses(thread);
// Write snapshot with object content.
- FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
- &isolate_snapshot_data_buffer, &malloc_allocator,
- NULL, NULL /* image_writer */);
+ MallocWriteStream vm_snapshot_data(FullSnapshotWriter::kInitialSize);
+ MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
+ FullSnapshotWriter writer(
+ Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
+ /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
writer.WriteFullSnapshot();
const Snapshot* snapshot =
- Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
+ Snapshot::SetupFromBuffer(isolate_snapshot_data.buffer());
ASSERT(snapshot->kind() == Snapshot::kFull);
benchmark->set_score(snapshot->length());
-
- free(vm_snapshot_data_buffer);
- free(isolate_snapshot_data_buffer);
}
BENCHMARK_SIZE(StandaloneSnapshotSize) {
@@ -560,8 +552,6 @@
"\n";
// Start an Isolate, load a script and create a full snapshot.
- uint8_t* vm_snapshot_data_buffer;
- uint8_t* isolate_snapshot_data_buffer;
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
@@ -573,17 +563,16 @@
Api::CheckAndFinalizePendingClasses(thread);
// Write snapshot with object content.
- FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
- &isolate_snapshot_data_buffer, &malloc_allocator,
- NULL, NULL /* image_writer */);
+ MallocWriteStream vm_snapshot_data(FullSnapshotWriter::kInitialSize);
+ MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
+ FullSnapshotWriter writer(
+ Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
+ /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
writer.WriteFullSnapshot();
const Snapshot* snapshot =
- Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
+ Snapshot::SetupFromBuffer(isolate_snapshot_data.buffer());
ASSERT(snapshot->kind() == Snapshot::kFull);
benchmark->set_score(snapshot->length());
-
- free(vm_snapshot_data_buffer);
- free(isolate_snapshot_data_buffer);
}
BENCHMARK(CreateMirrorSystem) {
diff --git a/runtime/vm/bss_relocs.cc b/runtime/vm/bss_relocs.cc
index 80f50f5..2cb3157 100644
--- a/runtime/vm/bss_relocs.cc
+++ b/runtime/vm/bss_relocs.cc
@@ -31,8 +31,8 @@
auto const instructions = reinterpret_cast<uword>(
current->isolate_group()->source()->snapshot_instructions);
uword dso_base;
- // For non-natively loaded snapshots, this is instead initialized in
- // LoadedElf::ResolveSymbols().
+ // Needed for assembly snapshots. For ELF snapshots, we set up the relocated
+ // address information directly in the text segment ImageHeader.
if (NativeSymbolResolver::LookupSharedObject(instructions, &dso_base)) {
InitializeBSSEntry(Relocation::InstructionsRelocatedAddress,
instructions - dso_base, bss_start);
diff --git a/runtime/vm/canonical_tables.h b/runtime/vm/canonical_tables.h
new file mode 100644
index 0000000..69b79eb
--- /dev/null
+++ b/runtime/vm/canonical_tables.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2016, 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.
+
+#ifndef RUNTIME_VM_CANONICAL_TABLES_H_
+#define RUNTIME_VM_CANONICAL_TABLES_H_
+
+#include "platform/assert.h"
+#include "vm/hash_table.h"
+#include "vm/object.h"
+
+namespace dart {
+
+template <typename CharType>
+class CharArray {
+ public:
+ CharArray(const CharType* data, intptr_t len) : data_(data), len_(len) {
+ hash_ = String::Hash(data, len);
+ }
+ StringPtr ToSymbol() const {
+ String& result = String::Handle(StringFrom(data_, len_, Heap::kOld));
+ result.SetCanonical();
+ result.SetHash(hash_);
+ return result.raw();
+ }
+ bool Equals(const String& other) const {
+ ASSERT(other.HasHash());
+ if (other.Hash() != hash_) {
+ return false;
+ }
+ return other.Equals(data_, len_);
+ }
+ intptr_t Hash() const { return hash_; }
+
+ private:
+ const CharType* data_;
+ intptr_t len_;
+ intptr_t hash_;
+};
+typedef CharArray<uint8_t> Latin1Array;
+typedef CharArray<uint16_t> UTF16Array;
+typedef CharArray<int32_t> UTF32Array;
+
+class StringSlice {
+ public:
+ StringSlice(const String& str, intptr_t begin_index, intptr_t length)
+ : str_(str), begin_index_(begin_index), len_(length) {
+ hash_ = is_all() ? str.Hash() : String::Hash(str, begin_index, length);
+ }
+ StringPtr ToSymbol() const;
+ bool Equals(const String& other) const {
+ ASSERT(other.HasHash());
+ if (other.Hash() != hash_) {
+ return false;
+ }
+ return other.Equals(str_, begin_index_, len_);
+ }
+ intptr_t Hash() const { return hash_; }
+
+ private:
+ bool is_all() const { return begin_index_ == 0 && len_ == str_.Length(); }
+ const String& str_;
+ intptr_t begin_index_;
+ intptr_t len_;
+ intptr_t hash_;
+};
+
+class ConcatString {
+ public:
+ ConcatString(const String& str1, const String& str2)
+ : str1_(str1), str2_(str2), hash_(String::HashConcat(str1, str2)) {}
+ StringPtr ToSymbol() const;
+ bool Equals(const String& other) const {
+ ASSERT(other.HasHash());
+ if (other.Hash() != hash_) {
+ return false;
+ }
+ return other.EqualsConcat(str1_, str2_);
+ }
+ intptr_t Hash() const { return hash_; }
+
+ private:
+ const String& str1_;
+ const String& str2_;
+ intptr_t hash_;
+};
+
+class SymbolTraits {
+ public:
+ static const char* Name() { return "SymbolTraits"; }
+ static bool ReportStats() { return false; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ const String& a_str = String::Cast(a);
+ const String& b_str = String::Cast(b);
+ ASSERT(a_str.HasHash());
+ ASSERT(b_str.HasHash());
+ if (a_str.Hash() != b_str.Hash()) {
+ return false;
+ }
+ intptr_t a_len = a_str.Length();
+ if (a_len != b_str.Length()) {
+ return false;
+ }
+ // Use a comparison which does not consider the state of the canonical bit.
+ return a_str.Equals(b_str, 0, a_len);
+ }
+ template <typename CharType>
+ static bool IsMatch(const CharArray<CharType>& array, const Object& obj) {
+ return array.Equals(String::Cast(obj));
+ }
+ static bool IsMatch(const StringSlice& slice, const Object& obj) {
+ return slice.Equals(String::Cast(obj));
+ }
+ static bool IsMatch(const ConcatString& concat, const Object& obj) {
+ return concat.Equals(String::Cast(obj));
+ }
+ static uword Hash(const Object& key) { return String::Cast(key).Hash(); }
+ template <typename CharType>
+ static uword Hash(const CharArray<CharType>& array) {
+ return array.Hash();
+ }
+ static uword Hash(const StringSlice& slice) { return slice.Hash(); }
+ static uword Hash(const ConcatString& concat) { return concat.Hash(); }
+ template <typename CharType>
+ static ObjectPtr NewKey(const CharArray<CharType>& array) {
+ return array.ToSymbol();
+ }
+ static ObjectPtr NewKey(const StringSlice& slice) { return slice.ToSymbol(); }
+ static ObjectPtr NewKey(const ConcatString& concat) {
+ return concat.ToSymbol();
+ }
+};
+typedef UnorderedHashSet<SymbolTraits> CanonicalStringSet;
+
+class CanonicalTypeKey {
+ public:
+ explicit CanonicalTypeKey(const Type& key) : key_(key) {}
+ bool Matches(const Type& arg) const { return key_.Equals(arg); }
+ uword Hash() const { return key_.Hash(); }
+ const Type& key_;
+
+ private:
+ DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical Type based on its hash.
+class CanonicalTypeTraits {
+ public:
+ static const char* Name() { return "CanonicalTypeTraits"; }
+ static bool ReportStats() { return false; }
+
+ // Called when growing the table.
+ static bool IsMatch(const Object& a, const Object& b) {
+ ASSERT(a.IsType() && b.IsType());
+ const Type& arg1 = Type::Cast(a);
+ const Type& arg2 = Type::Cast(b);
+ return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+ }
+ static bool IsMatch(const CanonicalTypeKey& a, const Object& b) {
+ ASSERT(b.IsType());
+ return a.Matches(Type::Cast(b));
+ }
+ static uword Hash(const Object& key) {
+ ASSERT(key.IsType());
+ return Type::Cast(key).Hash();
+ }
+ static uword Hash(const CanonicalTypeKey& key) { return key.Hash(); }
+ static ObjectPtr NewKey(const CanonicalTypeKey& obj) {
+ return obj.key_.raw();
+ }
+};
+typedef UnorderedHashSet<CanonicalTypeTraits> CanonicalTypeSet;
+
+class CanonicalTypeParameterKey {
+ public:
+ explicit CanonicalTypeParameterKey(const TypeParameter& key) : key_(key) {}
+ bool Matches(const TypeParameter& arg) const { return key_.Equals(arg); }
+ uword Hash() const { return key_.Hash(); }
+ const TypeParameter& key_;
+
+ private:
+ DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical TypeParameter based on its hash.
+class CanonicalTypeParameterTraits {
+ public:
+ static const char* Name() { return "CanonicalTypeParameterTraits"; }
+ static bool ReportStats() { return false; }
+
+ // Called when growing the table.
+ static bool IsMatch(const Object& a, const Object& b) {
+ ASSERT(a.IsTypeParameter() && b.IsTypeParameter());
+ const TypeParameter& arg1 = TypeParameter::Cast(a);
+ const TypeParameter& arg2 = TypeParameter::Cast(b);
+ return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+ }
+ static bool IsMatch(const CanonicalTypeParameterKey& a, const Object& b) {
+ ASSERT(b.IsTypeParameter());
+ return a.Matches(TypeParameter::Cast(b));
+ }
+ static uword Hash(const Object& key) {
+ ASSERT(key.IsTypeParameter());
+ return TypeParameter::Cast(key).Hash();
+ }
+ static uword Hash(const CanonicalTypeParameterKey& key) { return key.Hash(); }
+ static ObjectPtr NewKey(const CanonicalTypeParameterKey& obj) {
+ return obj.key_.raw();
+ }
+};
+typedef UnorderedHashSet<CanonicalTypeParameterTraits>
+ CanonicalTypeParameterSet;
+
+class CanonicalTypeArgumentsKey {
+ public:
+ explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {}
+ bool Matches(const TypeArguments& arg) const {
+ return key_.Equals(arg) && (key_.Hash() == arg.Hash());
+ }
+ uword Hash() const { return key_.Hash(); }
+ const TypeArguments& key_;
+
+ private:
+ DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical TypeArguments based on its hash.
+class CanonicalTypeArgumentsTraits {
+ public:
+ static const char* Name() { return "CanonicalTypeArgumentsTraits"; }
+ static bool ReportStats() { return false; }
+
+ // Called when growing the table.
+ static bool IsMatch(const Object& a, const Object& b) {
+ ASSERT(a.IsTypeArguments() && b.IsTypeArguments());
+ const TypeArguments& arg1 = TypeArguments::Cast(a);
+ const TypeArguments& arg2 = TypeArguments::Cast(b);
+ return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+ }
+ static bool IsMatch(const CanonicalTypeArgumentsKey& a, const Object& b) {
+ ASSERT(b.IsTypeArguments());
+ return a.Matches(TypeArguments::Cast(b));
+ }
+ static uword Hash(const Object& key) {
+ ASSERT(key.IsTypeArguments());
+ return TypeArguments::Cast(key).Hash();
+ }
+ static uword Hash(const CanonicalTypeArgumentsKey& key) { return key.Hash(); }
+ static ObjectPtr NewKey(const CanonicalTypeArgumentsKey& obj) {
+ return obj.key_.raw();
+ }
+};
+typedef UnorderedHashSet<CanonicalTypeArgumentsTraits>
+ CanonicalTypeArgumentsSet;
+
+} // namespace dart
+
+#endif // RUNTIME_VM_CANONICAL_TABLES_H_
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 9732d93..e2c1435 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -7,6 +7,7 @@
#include "vm/class_finalizer.h"
+#include "vm/canonical_tables.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/flags.h"
#include "vm/hash_table.h"
@@ -21,7 +22,6 @@
#include "vm/runtime_entry.h"
#include "vm/symbols.h"
#include "vm/timeline.h"
-#include "vm/type_table.h"
#include "vm/type_testing_stubs.h"
namespace dart {
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 0664cbb..97f9325 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -91,7 +91,8 @@
V(FutureOr) \
V(UserTag) \
V(TransferableTypedData) \
- V(WeakSerializationReference)
+ V(WeakSerializationReference) \
+ V(ImageHeader)
#define CLASS_LIST_ARRAYS(V) \
V(Array) \
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 1918244..d6436b7 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -9,6 +9,7 @@
#include "platform/assert.h"
#include "vm/bootstrap.h"
#include "vm/bss_relocs.h"
+#include "vm/canonical_tables.h"
#include "vm/class_id.h"
#include "vm/code_observers.h"
#include "vm/compiler/api/print_filter.h"
@@ -494,6 +495,25 @@
}
}
}
+
+ void PostLoadEarly(Deserializer* d, const Array& refs) {
+ if (d->isolate() == Dart::vm_isolate()) {
+ return;
+ }
+ CanonicalTypeArgumentsSet table(
+ d->zone(), d->isolate()->object_store()->canonical_type_arguments());
+ TypeArguments& type_arg = TypeArguments::Handle(d->zone());
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ type_arg ^= refs.At(i);
+ if (type_arg.IsCanonical()) {
+ bool present = table.Insert(type_arg);
+ // Two recursive types with different topology (and hashes) may be
+ // equal.
+ ASSERT(!present || type_arg.IsRecursive());
+ }
+ }
+ d->isolate()->object_store()->set_canonical_type_arguments(table.Release());
+ }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -1892,23 +1912,23 @@
code->ptr()->code_source_map_ = static_cast<CodeSourceMapPtr>(d->ReadRef());
#if !defined(DART_PRECOMPILED_RUNTIME)
- if (d->kind() == Snapshot::kFullJIT) {
- code->ptr()->deopt_info_array_ = static_cast<ArrayPtr>(d->ReadRef());
- code->ptr()->static_calls_target_table_ =
- static_cast<ArrayPtr>(d->ReadRef());
- }
+ if (d->kind() == Snapshot::kFullJIT) {
+ code->ptr()->deopt_info_array_ = static_cast<ArrayPtr>(d->ReadRef());
+ code->ptr()->static_calls_target_table_ =
+ static_cast<ArrayPtr>(d->ReadRef());
+ }
#endif // !DART_PRECOMPILED_RUNTIME
#if !defined(PRODUCT)
- code->ptr()->return_address_metadata_ = d->ReadRef();
- code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
- code->ptr()->comments_ = FLAG_code_comments
- ? static_cast<ArrayPtr>(d->ReadRef())
- : Array::null();
- code->ptr()->compile_timestamp_ = 0;
+ code->ptr()->return_address_metadata_ = d->ReadRef();
+ code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
+ code->ptr()->comments_ = FLAG_code_comments
+ ? static_cast<ArrayPtr>(d->ReadRef())
+ : Array::null();
+ code->ptr()->compile_timestamp_ = 0;
#endif
- code->ptr()->state_bits_ = d->Read<int32_t>();
+ code->ptr()->state_bits_ = d->Read<int32_t>();
}
void PostLoad(Deserializer* d, const Array& refs) {
@@ -3608,6 +3628,25 @@
}
}
+ void PostLoadEarly(Deserializer* d, const Array& refs) {
+ if (d->isolate() == Dart::vm_isolate()) {
+ return;
+ }
+ CanonicalTypeSet table(d->zone(),
+ d->isolate()->object_store()->canonical_types());
+ Type& type = Type::Handle(d->zone());
+ for (intptr_t i = canonical_start_index_; i < canonical_stop_index_; i++) {
+ type ^= refs.At(i);
+ if (type.IsCanonical()) {
+ bool present = table.Insert(type);
+ // Two recursive types with different topology (and hashes) may be
+ // equal.
+ ASSERT(!present || type.IsRecursive());
+ }
+ }
+ d->isolate()->object_store()->set_canonical_types(table.Release());
+ }
+
void PostLoad(Deserializer* d, const Array& refs) {
Type& type = Type::Handle(d->zone());
Code& stub = Code::Handle(d->zone());
@@ -3840,6 +3879,24 @@
}
}
+ void PostLoadEarly(Deserializer* d, const Array& refs) {
+ if (d->isolate() == Dart::vm_isolate()) {
+ return;
+ }
+ CanonicalTypeParameterSet table(
+ d->zone(), d->isolate()->object_store()->canonical_type_parameters());
+ TypeParameter& type_param = TypeParameter::Handle(d->zone());
+ for (intptr_t i = canonical_start_index_; i < canonical_stop_index_; i++) {
+ type_param ^= refs.At(i);
+ if (type_param.IsCanonical() && !type_param.IsDeclaration()) {
+ bool present = table.Insert(type_param);
+ ASSERT(!present);
+ }
+ }
+ d->isolate()->object_store()->set_canonical_type_parameters(
+ table.Release());
+ }
+
void PostLoad(Deserializer* d, const Array& refs) {
TypeParameter& type_param = TypeParameter::Handle(d->zone());
Code& stub = Code::Handle(d->zone());
@@ -4894,6 +4951,23 @@
String::SetCachedHash(str, hasher.Finalize());
}
}
+
+ void PostLoadEarly(Deserializer* d, const Array& refs) {
+ if (d->isolate() == Dart::vm_isolate()) {
+ return;
+ }
+ CanonicalStringSet table(d->zone(),
+ d->isolate()->object_store()->symbol_table());
+ String& str = String::Handle(d->zone());
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ str ^= refs.At(i);
+ if (str.IsCanonical()) {
+ bool present = table.Insert(str);
+ ASSERT(!present);
+ }
+ }
+ d->isolate()->object_store()->set_symbol_table(table.Release());
+ }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4974,6 +5048,23 @@
String::SetCachedHash(str, hasher.Finalize());
}
}
+
+ void PostLoadEarly(Deserializer* d, const Array& refs) {
+ if (d->isolate() == Dart::vm_isolate()) {
+ return;
+ }
+ CanonicalStringSet table(d->zone(),
+ d->isolate()->object_store()->symbol_table());
+ String& str = String::Handle(d->zone());
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ str ^= refs.At(i);
+ if (str.IsCanonical()) {
+ bool present = table.Insert(str);
+ ASSERT(!present);
+ }
+ }
+ d->isolate()->object_store()->set_symbol_table(table.Release());
+ }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -5204,7 +5295,36 @@
ObjectStore* object_store)
: num_base_objects_(num_base_objects),
object_store_(object_store),
- dispatch_table_entries_(Array::Handle()) {}
+ saved_symbol_table_(Array::Handle()),
+ saved_canonical_types_(Array::Handle()),
+ saved_canonical_type_parameters_(Array::Handle()),
+ saved_canonical_type_arguments_(Array::Handle()),
+ dispatch_table_entries_(Array::Handle()) {
+ saved_symbol_table_ = object_store->symbol_table();
+ object_store->set_symbol_table(
+ Array::Handle(HashTables::New<CanonicalStringSet>(4)));
+
+ saved_canonical_types_ = object_store->canonical_types();
+ object_store->set_canonical_types(
+ Array::Handle(HashTables::New<CanonicalTypeSet>(4)));
+
+ saved_canonical_type_parameters_ =
+ object_store->canonical_type_parameters();
+ object_store->set_canonical_type_parameters(
+ Array::Handle(HashTables::New<CanonicalTypeParameterSet>(4)));
+
+ saved_canonical_type_arguments_ = object_store->canonical_type_arguments();
+ object_store->set_canonical_type_arguments(
+ Array::Handle(HashTables::New<CanonicalTypeArgumentsSet>(4)));
+ }
+ ~ProgramSerializationRoots() {
+ object_store_->set_symbol_table(saved_symbol_table_);
+ object_store_->set_canonical_types(saved_canonical_types_);
+ object_store_->set_canonical_type_parameters(
+ saved_canonical_type_parameters_);
+ object_store_->set_canonical_type_arguments(
+ saved_canonical_type_arguments_);
+ }
void AddBaseObjects(Serializer* s) {
if (num_base_objects_ == 0) {
@@ -5257,6 +5377,10 @@
private:
intptr_t num_base_objects_;
ObjectStore* object_store_;
+ Array& saved_symbol_table_;
+ Array& saved_canonical_types_;
+ Array& saved_canonical_type_parameters_;
+ Array& saved_canonical_type_arguments_;
Array& dispatch_table_entries_;
};
#endif // !DART_PRECOMPILED_RUNTIME
@@ -5426,9 +5550,7 @@
Serializer::Serializer(Thread* thread,
Snapshot::Kind kind,
- uint8_t** buffer,
- ReAlloc alloc,
- intptr_t initial_size,
+ NonStreamingWriteStream* stream,
ImageWriter* image_writer,
bool vm,
V8SnapshotProfileWriter* profile_writer)
@@ -5436,7 +5558,7 @@
heap_(thread->isolate()->heap()),
zone_(thread->zone()),
kind_(kind),
- stream_(buffer, alloc, initial_size),
+ stream_(stream),
image_writer_(image_writer),
clusters_by_cid_(NULL),
stack_(),
@@ -5481,8 +5603,8 @@
// All bytes between objects are attributed into root node.
profile_writer_->AttributeBytesTo(
V8SnapshotProfileWriter::ArtificialRootId(),
- stream_.Position() - object_currently_writing_.stream_start_);
- object_currently_writing_.stream_start_ = stream_.Position();
+ stream_->Position() - object_currently_writing_.stream_start_);
+ object_currently_writing_.stream_start_ = stream_->Position();
}
#endif
}
@@ -5525,7 +5647,7 @@
FlushBytesWrittenToRoot();
object_currently_writing_.object_ = obj;
object_currently_writing_.id_ = id;
- object_currently_writing_.stream_start_ = stream_.Position();
+ object_currently_writing_.stream_start_ = stream_->Position();
object_currently_writing_.cid_ = cid;
profile_writer_->SetObjectTypeAndName(
{V8SnapshotProfileWriter::kSnapshot, id}, type, name);
@@ -5536,9 +5658,9 @@
ASSERT(IsAllocatedReference(object_currently_writing_.id_));
profile_writer_->AttributeBytesTo(
{V8SnapshotProfileWriter::kSnapshot, object_currently_writing_.id_},
- stream_.Position() - object_currently_writing_.stream_start_);
+ stream_->Position() - object_currently_writing_.stream_start_);
object_currently_writing_ = ProfilingObject();
- object_currently_writing_.stream_start_ = stream_.Position();
+ object_currently_writing_.stream_start_ = stream_->Position();
}
}
@@ -6087,7 +6209,7 @@
#endif
FlushBytesWrittenToRoot();
- object_currently_writing_.stream_start_ = stream_.Position();
+ object_currently_writing_.stream_start_ = stream_->Position();
PrintSnapshotSizes();
@@ -6218,7 +6340,7 @@
}
dispatch_table_size_ = bytes_written() - bytes_before;
- object_currently_writing_.stream_start_ = stream_.Position();
+ object_currently_writing_.stream_start_ = stream_->Position();
// If any bytes were written for the dispatch table, add it to the profile.
if (dispatch_table_size_ > 0 && profile_writer_ != nullptr) {
// Grab an unused ref index for a unique object id for the dispatch table.
@@ -6803,8 +6925,8 @@
for (intptr_t i = 0; i < num_clusters_; i++) {
clusters_[i]->ReadFill(this);
#if defined(DEBUG)
- int32_t section_marker = Read<int32_t>();
- ASSERT(section_marker == kSectionMarker);
+ int32_t section_marker = Read<int32_t>();
+ ASSERT(section_marker == kSectionMarker);
#endif
}
@@ -6829,23 +6951,30 @@
}
#endif
+ // TODO(rmacnak): When splitting literals, load clusters requiring
+ // canonicalization first, canonicalize and update the ref array, the load
+ // the remaining clusters to avoid a full heap walk to update references to
+ // the losers of any canonicalization races.
+ for (intptr_t i = 0; i < num_clusters_; i++) {
+ clusters_[i]->PostLoadEarly(this, refs);
+ }
+
for (intptr_t i = 0; i < num_clusters_; i++) {
clusters_[i]->PostLoad(this, refs);
}
}
#if !defined(DART_PRECOMPILED_RUNTIME)
-FullSnapshotWriter::FullSnapshotWriter(Snapshot::Kind kind,
- uint8_t** vm_snapshot_data_buffer,
- uint8_t** isolate_snapshot_data_buffer,
- ReAlloc alloc,
- ImageWriter* vm_image_writer,
- ImageWriter* isolate_image_writer)
+FullSnapshotWriter::FullSnapshotWriter(
+ Snapshot::Kind kind,
+ NonStreamingWriteStream* vm_snapshot_data,
+ NonStreamingWriteStream* isolate_snapshot_data,
+ ImageWriter* vm_image_writer,
+ ImageWriter* isolate_image_writer)
: thread_(Thread::Current()),
kind_(kind),
- vm_snapshot_data_buffer_(vm_snapshot_data_buffer),
- isolate_snapshot_data_buffer_(isolate_snapshot_data_buffer),
- alloc_(alloc),
+ vm_snapshot_data_(vm_snapshot_data),
+ isolate_snapshot_data_(isolate_snapshot_data),
vm_isolate_snapshot_size_(0),
isolate_snapshot_size_(0),
vm_image_writer_(vm_image_writer),
@@ -6854,7 +6983,6 @@
clustered_isolate_size_(0),
mapped_data_size_(0),
mapped_text_size_(0) {
- ASSERT(alloc_ != NULL);
ASSERT(isolate() != NULL);
ASSERT(heap() != NULL);
ObjectStore* object_store = isolate()->object_store();
@@ -6877,10 +7005,9 @@
intptr_t FullSnapshotWriter::WriteVMSnapshot() {
TIMELINE_DURATION(thread(), Isolate, "WriteVMSnapshot");
- ASSERT(vm_snapshot_data_buffer_ != NULL);
- Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
- kInitialSize, vm_image_writer_, /*vm=*/true,
- profile_writer_);
+ ASSERT(vm_snapshot_data_ != nullptr);
+ Serializer serializer(thread(), kind_, vm_snapshot_data_, vm_image_writer_,
+ /*vm=*/true, profile_writer_);
serializer.ReserveHeader();
serializer.WriteVersionAndFeatures(true);
@@ -6909,9 +7036,9 @@
GrowableArray<LoadingUnitSerializationData*>* units) {
TIMELINE_DURATION(thread(), Isolate, "WriteProgramSnapshot");
- Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
- kInitialSize, isolate_image_writer_, /*vm=*/false,
- profile_writer_);
+ ASSERT(isolate_snapshot_data_ != nullptr);
+ Serializer serializer(thread(), kind_, isolate_snapshot_data_,
+ isolate_image_writer_, /*vm=*/false, profile_writer_);
serializer.set_loading_units(units);
serializer.set_current_loading_unit_id(LoadingUnit::kRootId);
ObjectStore* object_store = isolate()->object_store();
@@ -6954,9 +7081,8 @@
uint32_t program_hash) {
TIMELINE_DURATION(thread(), Isolate, "WriteUnitSnapshot");
- Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
- kInitialSize, isolate_image_writer_, /*vm=*/false,
- profile_writer_);
+ Serializer serializer(thread(), kind_, isolate_snapshot_data_,
+ isolate_image_writer_, /*vm=*/false, profile_writer_);
serializer.set_loading_units(units);
serializer.set_current_loading_unit_id(unit->id());
@@ -6989,14 +7115,14 @@
void FullSnapshotWriter::WriteFullSnapshot(
GrowableArray<LoadingUnitSerializationData*>* data) {
intptr_t num_base_objects;
- if (vm_snapshot_data_buffer() != NULL) {
+ if (vm_snapshot_data_ != nullptr) {
num_base_objects = WriteVMSnapshot();
ASSERT(num_base_objects != 0);
} else {
num_base_objects = 0;
}
- if (isolate_snapshot_data_buffer() != NULL) {
+ if (isolate_snapshot_data_ != nullptr) {
WriteProgramSnapshot(num_base_objects, data);
}
@@ -7026,8 +7152,7 @@
buffer_(snapshot->Addr()),
size_(snapshot->length()),
data_image_(snapshot->DataImage()),
- instructions_image_(instructions_buffer) {
-}
+ instructions_image_(instructions_buffer) {}
char* SnapshotHeaderReader::InitializeGlobalVMFlagsFromSnapshot(
const Snapshot* snapshot) {
@@ -7217,12 +7342,8 @@
// Initialize entries in the VM portion of the BSS segment.
ASSERT(Snapshot::IncludesCode(kind_));
Image image(instructions_image_);
- if (image.bss_offset() != 0) {
- // The const cast is safe because we're translating from the start of the
- // instructions (read-only) to the start of the BSS (read-write).
- uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
- instructions_image_ + image.bss_offset()));
- BSS::Initialize(thread_, bss_start, /*vm=*/true);
+ if (auto const bss = image.bss()) {
+ BSS::Initialize(thread_, bss, /*vm=*/true);
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
@@ -7353,12 +7474,8 @@
// Initialize entries in the isolate portion of the BSS segment.
ASSERT(Snapshot::IncludesCode(kind_));
Image image(instructions_image_);
- if (image.bss_offset() != 0) {
- // The const cast is safe because we're translating from the start of the
- // instructions (read-only) to the start of the BSS (read-write).
- uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
- instructions_image_ + image.bss_offset()));
- BSS::Initialize(thread_, bss_start, /*vm=*/false);
+ if (auto const bss = image.bss()) {
+ BSS::Initialize(thread_, bss, /*vm=*/false);
}
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 2dd7253..4188c75 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -116,6 +116,7 @@
// Complete any action that requires the full graph to be deserialized, such
// as rehashing.
+ virtual void PostLoadEarly(Deserializer* deserializer, const Array& refs) {}
virtual void PostLoad(Deserializer* deserializer, const Array& refs) {}
protected:
@@ -192,9 +193,7 @@
public:
Serializer(Thread* thread,
Snapshot::Kind kind,
- uint8_t** buffer,
- ReAlloc alloc,
- intptr_t initial_size,
+ NonStreamingWriteStream* stream,
ImageWriter* image_writer_,
bool vm_,
V8SnapshotProfileWriter* profile_writer = nullptr);
@@ -271,13 +270,13 @@
void ReserveHeader() {
// Make room for recording snapshot buffer size.
- stream_.SetPosition(Snapshot::kHeaderSize);
+ stream_->SetPosition(Snapshot::kHeaderSize);
}
void FillHeader(Snapshot::Kind kind) {
- Snapshot* header = reinterpret_cast<Snapshot*>(stream_.buffer());
+ Snapshot* header = reinterpret_cast<Snapshot*>(stream_->buffer());
header->set_magic();
- header->set_length(stream_.bytes_written());
+ header->set_length(stream_->bytes_written());
header->set_kind(kind);
}
@@ -288,8 +287,8 @@
FieldTable* field_table() { return field_table_; }
- WriteStream* stream() { return &stream_; }
- intptr_t bytes_written() { return stream_.bytes_written(); }
+ NonStreamingWriteStream* stream() { return stream_; }
+ intptr_t bytes_written() { return stream_->bytes_written(); }
void FlushBytesWrittenToRoot();
void TraceStartWritingObject(const char* type, ObjectPtr obj, StringPtr name);
@@ -302,19 +301,19 @@
// sizeof(T) must be in {1,2,4,8}.
template <typename T>
void Write(T value) {
- WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
+ BaseWriteStream::Raw<sizeof(T), T>::Write(stream_, value);
}
- void WriteUnsigned(intptr_t value) { stream_.WriteUnsigned(value); }
- void WriteUnsigned64(uint64_t value) { stream_.WriteUnsigned(value); }
+ void WriteUnsigned(intptr_t value) { stream_->WriteUnsigned(value); }
+ void WriteUnsigned64(uint64_t value) { stream_->WriteUnsigned(value); }
void WriteWordWith32BitWrites(uword value) {
- stream_.WriteWordWith32BitWrites(value);
+ stream_->WriteWordWith32BitWrites(value);
}
void WriteBytes(const uint8_t* addr, intptr_t len) {
- stream_.WriteBytes(addr, len);
+ stream_->WriteBytes(addr, len);
}
- void Align(intptr_t alignment) { stream_.Align(alignment); }
+ void Align(intptr_t alignment) { stream_->Align(alignment); }
void WriteRootRef(ObjectPtr object, const char* name = nullptr) {
intptr_t id = RefId(object);
@@ -498,7 +497,7 @@
Heap* heap_;
Zone* zone_;
Snapshot::Kind kind_;
- WriteStream stream_;
+ NonStreamingWriteStream* stream_;
ImageWriter* image_writer_;
SerializationCluster** clusters_by_cid_;
GrowableArray<ObjectPtr> stack_;
@@ -739,19 +738,12 @@
public:
static const intptr_t kInitialSize = 64 * KB;
FullSnapshotWriter(Snapshot::Kind kind,
- uint8_t** vm_snapshot_data_buffer,
- uint8_t** isolate_snapshot_data_buffer,
- ReAlloc alloc,
+ NonStreamingWriteStream* vm_snapshot_data,
+ NonStreamingWriteStream* isolate_snapshot_data,
ImageWriter* vm_image_writer,
ImageWriter* iso_image_writer);
~FullSnapshotWriter();
- uint8_t** vm_snapshot_data_buffer() const { return vm_snapshot_data_buffer_; }
-
- uint8_t** isolate_snapshot_data_buffer() const {
- return isolate_snapshot_data_buffer_;
- }
-
Thread* thread() const { return thread_; }
Zone* zone() const { return thread_->zone(); }
Isolate* isolate() const { return thread_->isolate(); }
@@ -777,9 +769,8 @@
Thread* thread_;
Snapshot::Kind kind_;
- uint8_t** vm_snapshot_data_buffer_;
- uint8_t** isolate_snapshot_data_buffer_;
- ReAlloc alloc_;
+ NonStreamingWriteStream* const vm_snapshot_data_;
+ NonStreamingWriteStream* const isolate_snapshot_data_;
intptr_t vm_isolate_snapshot_size_;
intptr_t isolate_snapshot_size_;
ImageWriter* vm_image_writer_;
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index a462905..2dc5584 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -281,13 +281,6 @@
return handlers.raw();
}
-static uint8_t* ZoneAllocator(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- Zone* zone = Thread::Current()->zone();
- return zone->Realloc<uint8_t>(ptr, old_size, new_size);
-}
-
#if !defined(DART_PRECOMPILED_RUNTIME)
class CatchEntryMovesMapBuilder::TrieNode : public ZoneAllocated {
public:
@@ -319,8 +312,7 @@
: zone_(Thread::Current()->zone()),
root_(new TrieNode()),
current_pc_offset_(0),
- buffer_(NULL),
- stream_(&buffer_, ZoneAllocator, 64) {}
+ stream_(zone_, 64) {}
void CatchEntryMovesMapBuilder::Append(const CatchEntryMove& move) {
moves_.Add(move);
@@ -344,7 +336,7 @@
intptr_t length = moves_.length() - suffix_length;
intptr_t current_offset = stream_.bytes_written();
- typedef WriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
+ typedef ZoneWriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
Writer::Write(&stream_, current_pc_offset_);
Writer::Write(&stream_, length);
Writer::Write(&stream_, suffix_length);
@@ -378,6 +370,7 @@
TokenPosition(TokenPosition::kDartCodeProloguePos);
CodeSourceMapBuilder::CodeSourceMapBuilder(
+ Zone* zone,
bool stack_traces_only,
const GrowableArray<intptr_t>& caller_inline_id,
const GrowableArray<TokenPosition>& inline_id_to_token_pos,
@@ -393,8 +386,7 @@
inline_id_to_function_(inline_id_to_function),
inlined_functions_(
GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld))),
- buffer_(NULL),
- stream_(&buffer_, ZoneAllocator, 64),
+ stream_(zone, 64),
stack_traces_only_(stack_traces_only) {
buffered_inline_id_stack_.Add(0);
buffered_token_pos_stack_.Add(kInitialPosition);
@@ -567,7 +559,7 @@
intptr_t length = stream_.bytes_written();
const CodeSourceMap& map = CodeSourceMap::Handle(CodeSourceMap::New(length));
NoSafepointScope no_safepoint;
- memmove(map.Data(), buffer_, length);
+ memmove(map.Data(), stream_.buffer(), length);
return map.raw();
}
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index 6f89c91..bef3ef8 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -226,8 +226,7 @@
TrieNode* root_;
intptr_t current_pc_offset_;
GrowableArray<CatchEntryMove> moves_;
- uint8_t* buffer_;
- WriteStream stream_;
+ ZoneWriteStream stream_;
DISALLOW_COPY_AND_ASSIGN(CatchEntryMovesMapBuilder);
};
@@ -246,6 +245,7 @@
class CodeSourceMapBuilder : public ZoneAllocated {
public:
CodeSourceMapBuilder(
+ Zone* zone,
bool stack_traces_only,
const GrowableArray<intptr_t>& caller_inline_id,
const GrowableArray<TokenPosition>& inline_id_to_token_pos,
@@ -336,8 +336,7 @@
const GrowableObjectArray& inlined_functions_;
- uint8_t* buffer_;
- WriteStream stream_;
+ ZoneWriteStream stream_;
const bool stack_traces_only_;
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index 173652f..0db337d 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -429,7 +429,7 @@
}
}
-TypeFeedbackSaver::TypeFeedbackSaver(WriteStream* stream)
+TypeFeedbackSaver::TypeFeedbackSaver(BaseWriteStream* stream)
: stream_(stream),
cls_(Class::Handle()),
lib_(Library::Handle()),
diff --git a/runtime/vm/compilation_trace.h b/runtime/vm/compilation_trace.h
index cf26611..80d671e 100644
--- a/runtime/vm/compilation_trace.h
+++ b/runtime/vm/compilation_trace.h
@@ -67,7 +67,7 @@
class TypeFeedbackSaver : public FunctionVisitor {
public:
- explicit TypeFeedbackSaver(WriteStream* stream);
+ explicit TypeFeedbackSaver(BaseWriteStream* stream);
void WriteHeader();
void SaveClasses();
@@ -79,7 +79,7 @@
void WriteString(const String& value);
void WriteInt(intptr_t value) { stream_->Write(static_cast<int32_t>(value)); }
- WriteStream* const stream_;
+ BaseWriteStream* const stream_;
Class& cls_;
Library& lib_;
String& str_;
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 878ce4a..1f31fd0 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -5,6 +5,7 @@
#include "vm/compiler/aot/precompiler.h"
#include "platform/unicode.h"
+#include "vm/canonical_tables.h"
#include "vm/class_finalizer.h"
#include "vm/code_patcher.h"
#include "vm/compiler/aot/aot_call_specializer.h"
@@ -48,7 +49,6 @@
#include "vm/tags.h"
#include "vm/timeline.h"
#include "vm/timer.h"
-#include "vm/type_table.h"
#include "vm/type_testing_stubs.h"
#include "vm/version.h"
#include "vm/zone_text_buffer.h"
@@ -449,8 +449,6 @@
Symbols::GetStats(I, &symbols_before, &capacity);
}
- Symbols::Compact();
-
if (FLAG_trace_precompiler) {
Symbols::GetStats(I, &symbols_after, &capacity);
THR_Print("Precompiled %" Pd " functions,", function_count_);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 9c7eabc..361ccbe 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -164,7 +164,7 @@
const bool stack_traces_only = false;
#endif
code_source_map_builder_ = new (zone_)
- CodeSourceMapBuilder(stack_traces_only, caller_inline_id,
+ CodeSourceMapBuilder(zone_, stack_traces_only, caller_inline_id,
inline_id_to_token_pos, inline_id_to_function);
ArchSpecificInitialization();
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index bb55bba..e736c7a 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1580,6 +1580,7 @@
VariableDeclarationHelper helper(&helper_);
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
String& name = H.DartSymbolObfuscate(helper.name_index_);
+ ASSERT(name.Length() > 0);
AbstractType& type = BuildAndVisitVariableType(); // read type.
helper.SetJustRead(VariableDeclarationHelper::kType);
helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 0aecfbd..c313f53 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -800,6 +800,10 @@
return 0;
}
+word ImageHeader::InstanceSize() {
+ return RoundedAllocationSize(UnroundedSize());
+}
+
word Instance::NextFieldOffset() {
return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
}
@@ -808,6 +812,10 @@
return TranslateOffsetInWords(dart::Pointer::NextFieldOffset());
}
+word ImageHeader::NextFieldOffset() {
+ return -kWordSize;
+}
+
word WeakSerializationReference::NextFieldOffset() {
return -kWordSize;
}
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 1a75739..5ec71e8 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1179,6 +1179,13 @@
static word NextFieldOffset();
};
+class ImageHeader : public AllStatic {
+ public:
+ static word UnroundedSize();
+ static word InstanceSize();
+ static word NextFieldOffset();
+};
+
class WeakSerializationReference : public AllStatic {
public:
static word InstanceSize();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 4994749..6ad8752 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -454,6 +454,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -966,6 +967,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -1469,6 +1471,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -1982,6 +1985,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -2484,6 +2488,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -2990,6 +2995,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -3487,6 +3493,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
16;
static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -3994,6 +4001,7 @@
static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
32;
static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -4542,6 +4550,8 @@
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 16;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+ 20;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word
@@ -5105,6 +5115,8 @@
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+ 40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -5673,6 +5685,8 @@
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+ 40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -6229,6 +6243,8 @@
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 16;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+ 20;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
static constexpr dart::compiler::target::word
@@ -6785,6 +6801,8 @@
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+ 40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
@@ -7346,6 +7364,8 @@
static constexpr dart::compiler::target::word
AOT_GrowableObjectArray_InstanceSize = 32;
static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+ 40;
static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
12;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 6f1dcb6..01874c4 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -306,6 +306,7 @@
SIZEOF(FutureOr, InstanceSize, FutureOrLayout) \
SIZEOF(GrowableObjectArray, InstanceSize, GrowableObjectArrayLayout) \
SIZEOF(ICData, InstanceSize, ICDataLayout) \
+ SIZEOF(ImageHeader, UnroundedSize, ImageHeaderLayout) \
SIZEOF(Instance, InstanceSize, InstanceLayout) \
SIZEOF(Instructions, InstanceSize, InstructionsLayout) \
SIZEOF(Instructions, UnalignedHeaderSize, InstructionsLayout) \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 63ba037..e8bcf03 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1928,16 +1928,6 @@
Thread::ExitIsolate();
}
-#if !defined(DART_PRECOMPILED_RUNTIME)
-static uint8_t* ApiReallocate(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- return Api::TopScope(Thread::Current())
- ->zone()
- ->Realloc<uint8_t>(ptr, old_size, new_size);
-}
-#endif
-
DART_EXPORT Dart_Handle
Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
intptr_t* vm_snapshot_data_size,
@@ -1949,8 +1939,8 @@
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
- if (vm_snapshot_data_buffer != NULL && vm_snapshot_data_size == NULL) {
- RETURN_NULL_ERROR(vm_snapshot_data_size);
+ if (vm_snapshot_data_buffer != nullptr) {
+ CHECK_NULL(vm_snapshot_data_size);
}
CHECK_NULL(isolate_snapshot_data_buffer);
CHECK_NULL(isolate_snapshot_data_size);
@@ -1970,16 +1960,19 @@
}
#endif // #if defined(DEBUG)
- Symbols::Compact();
-
- FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
- isolate_snapshot_data_buffer, ApiReallocate,
- NULL /* vm_image_writer */,
- NULL /* isolate_image_writer */);
+ ZoneWriteStream vm_snapshot_data(Api::TopScope(T)->zone(),
+ FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
+ FullSnapshotWriter::kInitialSize);
+ FullSnapshotWriter writer(
+ Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
+ nullptr /* vm_image_writer */, nullptr /* isolate_image_writer */);
writer.WriteFullSnapshot();
- if (vm_snapshot_data_buffer != NULL) {
+ if (vm_snapshot_data_buffer != nullptr) {
+ *vm_snapshot_data_buffer = vm_snapshot_data.buffer();
*vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
}
+ *isolate_snapshot_data_buffer = isolate_snapshot_data.buffer();
*isolate_snapshot_data_size = writer.IsolateSnapshotSize();
return Api::Success();
#endif
@@ -6546,12 +6539,13 @@
CHECK_NULL(buffer);
CHECK_NULL(buffer_length);
- WriteStream stream(buffer, ApiReallocate, MB);
+ ZoneWriteStream stream(Api::TopScope(thread)->zone(), MB);
TypeFeedbackSaver saver(&stream);
saver.WriteHeader();
saver.SaveClasses();
saver.SaveFields();
ProgramVisitor::WalkProgram(thread->zone(), thread->isolate(), &saver);
+ *buffer = stream.buffer();
*buffer_length = stream.bytes_written();
return Api::Success();
@@ -6648,6 +6642,7 @@
// Used for StreamingWriteStream/BlobImageWriter sizes for ELF and blobs.
#if !defined(TARGET_ARCH_IA32) && defined(DART_PRECOMPILER)
+static const intptr_t kAssemblyInitialSize = 512 * KB;
static const intptr_t kInitialSize = 2 * MB;
static const intptr_t kInitialDebugSize = 1 * MB;
@@ -6665,10 +6660,11 @@
NOT_IN_PRODUCT(TimelineBeginEndScope tbes2(T, Timeline::GetIsolateStream(),
"WriteAppAOTSnapshot"));
- uint8_t* vm_snapshot_data_buffer = nullptr;
- uint8_t* vm_snapshot_instructions_buffer = nullptr;
- uint8_t* isolate_snapshot_data_buffer = nullptr;
- uint8_t* isolate_snapshot_instructions_buffer = nullptr;
+ ZoneWriteStream vm_snapshot_data(T->zone(), FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream vm_snapshot_instructions(T->zone(), kInitialSize);
+ ZoneWriteStream isolate_snapshot_data(T->zone(),
+ FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream isolate_snapshot_instructions(T->zone(), kInitialSize);
const bool generate_debug = debug_callback_data != nullptr;
@@ -6685,15 +6681,13 @@
strip ? new (Z) Dwarf(Z) : dwarf)
: nullptr;
- BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions_buffer,
- ApiReallocate, kInitialSize, debug_elf,
+ BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions, debug_elf,
elf);
- BlobImageWriter isolate_image_writer(
- T, &isolate_snapshot_instructions_buffer, ApiReallocate, kInitialSize,
- debug_elf, elf);
- FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
- &isolate_snapshot_data_buffer, ApiReallocate,
- &vm_image_writer, &isolate_image_writer);
+ BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions,
+ debug_elf, elf);
+ FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
+ &isolate_snapshot_data, &vm_image_writer,
+ &isolate_image_writer);
if (unit == nullptr || unit->id() == LoadingUnit::kRootId) {
writer.WriteFullSnapshot(units);
@@ -6706,6 +6700,8 @@
debug_elf->Finalize();
}
} else {
+ StreamingWriteStream assembly_stream(kAssemblyInitialSize, callback,
+ callback_data);
StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
callback, debug_callback_data);
@@ -6714,12 +6710,10 @@
new (Z) Dwarf(Z))
: nullptr;
- AssemblyImageWriter image_writer(T, callback, callback_data, strip, elf);
- uint8_t* vm_snapshot_data_buffer = NULL;
- uint8_t* isolate_snapshot_data_buffer = NULL;
- FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
- &isolate_snapshot_data_buffer, ApiReallocate,
- &image_writer, &image_writer);
+ AssemblyImageWriter image_writer(T, &assembly_stream, strip, elf);
+ FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
+ &isolate_snapshot_data, &image_writer,
+ &image_writer);
if (unit == nullptr || unit->id() == LoadingUnit::kRootId) {
writer.WriteFullSnapshot(units);
@@ -6849,10 +6843,12 @@
CHECK_NULL(callback);
TIMELINE_DURATION(T, Isolate, "WriteVMAOTSnapshot");
- AssemblyImageWriter image_writer(T, callback, callback_data);
- uint8_t* vm_snapshot_data_buffer = nullptr;
- FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
- nullptr, ApiReallocate, &image_writer, nullptr);
+ StreamingWriteStream assembly_stream(kAssemblyInitialSize, callback,
+ callback_data);
+ AssemblyImageWriter image_writer(T, &assembly_stream);
+ ZoneWriteStream vm_snapshot_data(T->zone(), FullSnapshotWriter::kInitialSize);
+ FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data, nullptr,
+ &image_writer, nullptr);
writer.WriteFullSnapshot();
@@ -7021,24 +7017,34 @@
DropRegExpMatchCode(Z);
ProgramVisitor::Dedup(T);
- Symbols::Compact();
TIMELINE_DURATION(T, Isolate, "WriteCoreJITSnapshot");
- BlobImageWriter vm_image_writer(T, vm_snapshot_instructions_buffer,
- ApiReallocate, 2 * MB /* initial_size */);
- BlobImageWriter isolate_image_writer(T, isolate_snapshot_instructions_buffer,
- ApiReallocate,
- 2 * MB /* initial_size */);
- FullSnapshotWriter writer(Snapshot::kFullJIT, vm_snapshot_data_buffer,
- isolate_snapshot_data_buffer, ApiReallocate,
- &vm_image_writer, &isolate_image_writer);
+ ZoneWriteStream vm_snapshot_data(Api::TopScope(T)->zone(),
+ FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream vm_snapshot_instructions(Api::TopScope(T)->zone(),
+ FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
+ FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream isolate_snapshot_instructions(
+ Api::TopScope(T)->zone(), FullSnapshotWriter::kInitialSize);
+
+ BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions);
+ BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions);
+ FullSnapshotWriter writer(Snapshot::kFullJIT, &vm_snapshot_data,
+ &isolate_snapshot_data, &vm_image_writer,
+ &isolate_image_writer);
writer.WriteFullSnapshot();
- *vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
- *vm_snapshot_instructions_size = vm_image_writer.InstructionsBlobSize();
- *isolate_snapshot_data_size = writer.IsolateSnapshotSize();
+ *vm_snapshot_data_buffer = vm_snapshot_data.buffer();
+ *vm_snapshot_data_size = vm_snapshot_data.bytes_written();
+ *vm_snapshot_instructions_buffer = vm_snapshot_instructions.buffer();
+ *vm_snapshot_instructions_size = vm_snapshot_instructions.bytes_written();
+ *isolate_snapshot_data_buffer = isolate_snapshot_data.buffer();
+ *isolate_snapshot_data_size = isolate_snapshot_data.bytes_written();
+ *isolate_snapshot_instructions_buffer =
+ isolate_snapshot_instructions.buffer();
*isolate_snapshot_instructions_size =
- isolate_image_writer.InstructionsBlobSize();
+ isolate_snapshot_instructions.bytes_written();
return Api::Success();
#endif
@@ -7097,7 +7103,6 @@
DropRegExpMatchCode(Z);
ProgramVisitor::Dedup(T);
- Symbols::Compact();
if (FLAG_dump_tables) {
Symbols::DumpTable(I);
@@ -7107,17 +7112,21 @@
}
TIMELINE_DURATION(T, Isolate, "WriteAppJITSnapshot");
- BlobImageWriter isolate_image_writer(T, isolate_snapshot_instructions_buffer,
- ApiReallocate,
- 2 * MB /* initial_size */);
- FullSnapshotWriter writer(Snapshot::kFullJIT, NULL,
- isolate_snapshot_data_buffer, ApiReallocate, NULL,
- &isolate_image_writer);
+ ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
+ FullSnapshotWriter::kInitialSize);
+ ZoneWriteStream isolate_snapshot_instructions(
+ Api::TopScope(T)->zone(), FullSnapshotWriter::kInitialSize);
+ BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions);
+ FullSnapshotWriter writer(Snapshot::kFullJIT, nullptr, &isolate_snapshot_data,
+ nullptr, &isolate_image_writer);
writer.WriteFullSnapshot();
- *isolate_snapshot_data_size = writer.IsolateSnapshotSize();
+ *isolate_snapshot_data_buffer = isolate_snapshot_data.buffer();
+ *isolate_snapshot_data_size = isolate_snapshot_data.bytes_written();
+ *isolate_snapshot_instructions_buffer =
+ isolate_snapshot_instructions.buffer();
*isolate_snapshot_instructions_size =
- isolate_image_writer.InstructionsBlobSize();
+ isolate_snapshot_instructions.bytes_written();
return Api::Success();
#endif
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 613614e..bc83266 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -774,15 +774,8 @@
return NULL;
}
-static uint8_t* malloc_allocator(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
- return reinterpret_cast<uint8_t*>(new_ptr);
-}
-
ApiMessageWriter::ApiMessageWriter()
- : BaseWriter(malloc_allocator, NULL, kInitialSize),
+ : BaseWriter(kInitialSize),
object_id_(0),
forward_list_(NULL),
forward_list_length_(0),
@@ -1170,7 +1163,8 @@
bool success = WriteCObject(object);
if (!success) {
UnmarkAllCObjects(object);
- free(buffer());
+ intptr_t unused;
+ free(Steal(&unused));
return nullptr;
}
@@ -1181,16 +1175,18 @@
success = WriteForwardedCObject(forward_list_[i]);
if (!success) {
UnmarkAllCObjects(object);
- free(buffer());
+ intptr_t unused;
+ free(Steal(&unused));
return nullptr;
}
}
UnmarkAllCObjects(object);
MessageFinalizableData* finalizable_data = finalizable_data_;
- finalizable_data_ = NULL;
- return Message::New(dest_port, buffer(), BytesWritten(), finalizable_data,
- priority);
+ finalizable_data_ = nullptr;
+ intptr_t size;
+ uint8_t* buffer = Steal(&size);
+ return Message::New(dest_port, buffer, size, finalizable_data, priority);
}
} // namespace dart
diff --git a/runtime/vm/datastream.cc b/runtime/vm/datastream.cc
index de77937..a87cf46 100644
--- a/runtime/vm/datastream.cc
+++ b/runtime/vm/datastream.cc
@@ -3,19 +3,26 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/datastream.h"
+#include "vm/zone.h"
namespace dart {
-StreamingWriteStream::StreamingWriteStream(intptr_t initial_capacity,
- Dart_StreamingWriteCallback callback,
- void* callback_data)
- : flushed_size_(0), callback_(callback), callback_data_(callback_data) {
- buffer_ = reinterpret_cast<uint8_t*>(malloc(initial_capacity));
- if (buffer_ == NULL) {
- OUT_OF_MEMORY();
- }
- cursor_ = buffer_;
- limit_ = buffer_ + initial_capacity;
+MallocWriteStream::~MallocWriteStream() {
+ free(buffer_);
+}
+
+void MallocWriteStream::Realloc(intptr_t new_size) {
+ const intptr_t old_offset = current_ - buffer_;
+ buffer_ = reinterpret_cast<uint8_t*>(realloc(buffer_, new_size));
+ capacity_ = buffer_ != nullptr ? new_size : 0;
+ current_ = buffer_ != nullptr ? buffer_ + old_offset : nullptr;
+}
+
+void ZoneWriteStream::Realloc(intptr_t new_size) {
+ const intptr_t old_offset = current_ - buffer_;
+ buffer_ = zone_->Realloc(buffer_, capacity_, new_size);
+ capacity_ = buffer_ != nullptr ? new_size : 0;
+ current_ = buffer_ != nullptr ? buffer_ + old_offset : nullptr;
}
StreamingWriteStream::~StreamingWriteStream() {
@@ -23,46 +30,23 @@
free(buffer_);
}
-void StreamingWriteStream::VPrint(const char* format, va_list args) {
- // Measure.
- va_list measure_args;
- va_copy(measure_args, args);
- intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
- va_end(measure_args);
-
- // Alloc.
- EnsureAvailable(len + 1);
-
- // Print.
- va_list print_args;
- va_copy(print_args, args);
- Utils::VSNPrint(reinterpret_cast<char*>(cursor_), len + 1, format,
- print_args);
- va_end(print_args);
- cursor_ += len; // Not len + 1 to swallow the terminating NUL.
-}
-
-void StreamingWriteStream::EnsureAvailableSlowPath(intptr_t needed) {
+void StreamingWriteStream::Realloc(intptr_t new_size) {
Flush();
-
- intptr_t available = limit_ - cursor_;
- if (available >= needed) return;
-
- intptr_t new_capacity = Utils::RoundUp(needed, 64 * KB);
- free(buffer_);
- buffer_ = reinterpret_cast<uint8_t*>(malloc(new_capacity));
- if (buffer_ == NULL) {
- OUT_OF_MEMORY();
+ // Check whether resetting the internal buffer by flushing gave enough space.
+ if (new_size <= capacity_) {
+ return;
}
- cursor_ = buffer_;
- limit_ = buffer_ + new_capacity;
+ const intptr_t new_capacity = Utils::RoundUp(new_size, 64 * KB);
+ buffer_ = reinterpret_cast<uint8_t*>(realloc(buffer_, new_capacity));
+ capacity_ = buffer_ != nullptr ? new_capacity : 0;
+ current_ = buffer_; // Flushing reset the internal buffer offset to 0.
}
void StreamingWriteStream::Flush() {
- intptr_t size = cursor_ - buffer_;
+ intptr_t size = current_ - buffer_;
callback_(callback_data_, buffer_, size);
flushed_size_ += size;
- cursor_ = buffer_;
+ current_ = buffer_;
}
} // namespace dart
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index a844493..39acb48 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -5,13 +5,13 @@
#ifndef RUNTIME_VM_DATASTREAM_H_
#define RUNTIME_VM_DATASTREAM_H_
-#include "include/dart_api.h"
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/allocation.h"
#include "vm/exceptions.h"
#include "vm/globals.h"
#include "vm/os.h"
+#include "vm/zone.h"
namespace dart {
@@ -23,9 +23,6 @@
static const uint8_t kEndByteMarker = (255 - kMaxDataPerByte);
static const uint8_t kEndUnsignedByteMarker = (255 - kMaxUnsignedDataPerByte);
-typedef uint8_t* (*ReAlloc)(uint8_t* ptr, intptr_t old_size, intptr_t new_size);
-typedef void (*DeAlloc)(uint8_t* ptr);
-
// Stream for reading various types from a buffer.
class ReadStream : public ValueObject {
public:
@@ -308,38 +305,23 @@
DISALLOW_COPY_AND_ASSIGN(ReadStream);
};
-// Stream for writing various types into a buffer.
-class WriteStream : public ValueObject {
+// Base class for streams that writing various types into a buffer, possibly
+// flushing data out periodically to a more permanent store.
+class BaseWriteStream : public ValueObject {
public:
- WriteStream(uint8_t** buffer, ReAlloc alloc, intptr_t initial_size)
- : buffer_(buffer),
- end_(NULL),
- current_(NULL),
- current_size_(0),
- alloc_(alloc),
- initial_size_(initial_size) {
- ASSERT(buffer != NULL);
- ASSERT(alloc != NULL);
- *buffer_ = reinterpret_cast<uint8_t*>(alloc_(NULL, 0, initial_size_));
- if (*buffer_ == NULL) {
- Exceptions::ThrowOOM();
- }
- current_ = *buffer_;
- current_size_ = initial_size_;
- end_ = *buffer_ + initial_size_;
- }
+ explicit BaseWriteStream(intptr_t initial_size)
+ : initial_size_(Utils::RoundUpToPowerOfTwo(initial_size)) {}
+ virtual ~BaseWriteStream() {}
- uint8_t* buffer() const { return *buffer_; }
- void set_buffer(uint8_t* value) { *buffer_ = value; }
- intptr_t bytes_written() const { return current_ - *buffer_; }
-
- intptr_t Position() const { return current_ - *buffer_; }
- void SetPosition(intptr_t value) { current_ = *buffer_ + value; }
+ DART_FORCE_INLINE intptr_t bytes_written() const { return Position(); }
+ virtual intptr_t Position() const { return current_ - buffer_; }
void Align(intptr_t alignment) {
- intptr_t position_before = Position();
- intptr_t position_after = Utils::RoundUp(position_before, alignment);
- memset(current_, 0, position_after - position_before);
+ const intptr_t position_before = Position();
+ const intptr_t position_after = Utils::RoundUp(position_before, alignment);
+ const intptr_t length = position_after - position_before;
+ EnsureSpace(length);
+ memset(current_, 0, length);
SetPosition(position_after);
}
@@ -349,7 +331,7 @@
template <typename T>
class Raw<1, T> {
public:
- static void Write(WriteStream* st, T value) {
+ static void Write(BaseWriteStream* st, T value) {
st->WriteByte(bit_cast<int8_t>(value));
}
};
@@ -357,7 +339,7 @@
template <typename T>
class Raw<2, T> {
public:
- static void Write(WriteStream* st, T value) {
+ static void Write(BaseWriteStream* st, T value) {
st->Write<int16_t>(bit_cast<int16_t>(value));
}
};
@@ -365,7 +347,7 @@
template <typename T>
class Raw<4, T> {
public:
- static void Write(WriteStream* st, T value) {
+ static void Write(BaseWriteStream* st, T value) {
st->Write<int32_t>(bit_cast<int32_t>(value));
}
};
@@ -373,7 +355,7 @@
template <typename T>
class Raw<8, T> {
public:
- static void Write(WriteStream* st, T value) {
+ static void Write(BaseWriteStream* st, T value) {
st->Write<int64_t>(bit_cast<int64_t>(value));
}
};
@@ -401,10 +383,7 @@
}
void WriteBytes(const void* addr, intptr_t len) {
- if ((end_ - current_) < len) {
- Resize(len);
- }
- ASSERT((end_ - current_) >= len);
+ EnsureSpace(len);
if (len != 0) {
memmove(current_, addr, len);
}
@@ -413,10 +392,7 @@
void WriteWord(uword value) {
const intptr_t len = sizeof(uword);
- if ((end_ - current_) < len) {
- Resize(len);
- }
- ASSERT((end_ - current_) >= len);
+ EnsureSpace(len);
*reinterpret_cast<uword*>(current_) = value;
current_ += len;
}
@@ -425,10 +401,7 @@
#if defined(IS_SIMARM_X64)
RELEASE_ASSERT(Utils::IsInt(32, static_cast<word>(value)));
const intptr_t len = sizeof(uint32_t);
- if ((end_ - current_) < len) {
- Resize(len);
- }
- ASSERT((end_ - current_) >= len);
+ EnsureSpace(len);
*reinterpret_cast<uint32_t*>(current_) = static_cast<uint32_t>(value);
current_ += len;
#else // defined(IS_SIMARM_X64)
@@ -451,10 +424,7 @@
va_end(measure_args);
// Alloc.
- if ((end_ - current_) < (len + 1)) {
- Resize(len + 1);
- }
- ASSERT((end_ - current_) >= (len + 1));
+ EnsureSpace(len + 1);
// Print.
va_list print_args;
@@ -478,101 +448,161 @@
template <typename T>
void WriteFixed(T value) {
const intptr_t len = sizeof(T);
- if ((end_ - current_) < len) {
- Resize(len);
- }
- ASSERT((end_ - current_) >= len);
+ EnsureSpace(len);
*reinterpret_cast<T*>(current_) = static_cast<T>(value);
current_ += len;
}
- private:
+ protected:
DART_FORCE_INLINE void WriteByte(uint8_t value) {
- if (current_ >= end_) {
- Resize(1);
- }
- ASSERT(current_ < end_);
+ EnsureSpace(1);
*current_++ = value;
}
- void Resize(intptr_t size_needed) {
- intptr_t position = current_ - *buffer_;
- intptr_t increment_size = current_size_;
+ void EnsureSpace(intptr_t size_needed) {
+ if (Remaining() >= size_needed) return;
+ intptr_t increment_size = capacity_;
if (size_needed > increment_size) {
increment_size = Utils::RoundUp(size_needed, initial_size_);
}
- intptr_t new_size = current_size_ + increment_size;
- ASSERT(new_size > current_size_);
- *buffer_ =
- reinterpret_cast<uint8_t*>(alloc_(*buffer_, current_size_, new_size));
- if (*buffer_ == NULL) {
+ intptr_t new_size = capacity_ + increment_size;
+ ASSERT(new_size > capacity_);
+ Realloc(new_size);
+ if (buffer_ == nullptr) {
Exceptions::ThrowOOM();
}
- current_ = *buffer_ + position;
- current_size_ = new_size;
- end_ = *buffer_ + new_size;
- ASSERT(end_ > *buffer_);
+ ASSERT(Remaining() >= size_needed);
+ }
+
+ virtual void SetPosition(intptr_t value) {
+ EnsureSpace(value - BaseWriteStream::Position());
+ current_ = buffer_ + value;
+ }
+
+ DART_FORCE_INLINE intptr_t Remaining() const {
+ return capacity_ - BaseWriteStream::Position();
+ }
+
+ // Resizes the internal buffer to the requested new capacity. Should set
+ // buffer_, capacity_, and current_ appropriately.
+ //
+ // Instead of templating over an Allocator (which would then cause users
+ // of the templated class to need to be templated, etc.), we just add an
+ // Realloc method to override appropriately in subclasses. Less flexible,
+ // but requires less changes throughout the codebase.
+ virtual void Realloc(intptr_t new_capacity) = 0;
+
+ const intptr_t initial_size_;
+ uint8_t* buffer_ = nullptr;
+ uint8_t* current_ = nullptr;
+ intptr_t capacity_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseWriteStream);
+};
+
+// A base class for non-streaming write streams. Since these streams are
+// not flushed periodically, the internal buffer contains all written data
+// and can be retrieved via buffer(). NonStreamingWriteStream also provides
+// SetPosition as part of its public API for non-sequential writing.
+class NonStreamingWriteStream : public BaseWriteStream {
+ public:
+ explicit NonStreamingWriteStream(intptr_t initial_size)
+ : BaseWriteStream(initial_size) {}
+
+ public:
+ uint8_t* buffer() const { return buffer_; }
+
+ // Sets the position of the buffer
+ DART_FORCE_INLINE void SetPosition(intptr_t value) {
+ BaseWriteStream::SetPosition(value);
+ }
+};
+
+// A non-streaming write stream that uses realloc for reallocation, and frees
+// the buffer when destructed unless ownership is transfered using Steal().
+class MallocWriteStream : public NonStreamingWriteStream {
+ public:
+ explicit MallocWriteStream(intptr_t initial_size)
+ : NonStreamingWriteStream(initial_size) {
+ // Go ahead and allocate initial space at construction.
+ EnsureSpace(initial_size_);
+ }
+ ~MallocWriteStream();
+
+ // Resets the stream and returns the original buffer, which is now considered
+ // owned by the caller. Sets [*length] to the length of the returned buffer.
+ uint8_t* Steal(intptr_t* length) {
+ ASSERT(length != nullptr);
+ *length = bytes_written();
+ uint8_t* const old_buffer = buffer_;
+ // We don't immediately reallocate a new space just in case this steal
+ // is the last use of this stream.
+ current_ = buffer_ = nullptr;
+ capacity_ = 0;
+ return old_buffer;
}
private:
- uint8_t** const buffer_;
- uint8_t* end_;
- uint8_t* current_;
- intptr_t current_size_;
- ReAlloc alloc_;
- intptr_t initial_size_;
+ virtual void Realloc(intptr_t new_size);
- DISALLOW_COPY_AND_ASSIGN(WriteStream);
+ DISALLOW_COPY_AND_ASSIGN(MallocWriteStream);
};
-class StreamingWriteStream : public ValueObject {
+// A non-streaming write stream that uses a zone for reallocation.
+class ZoneWriteStream : public NonStreamingWriteStream {
+ public:
+ ZoneWriteStream(Zone* zone, intptr_t initial_size)
+ : NonStreamingWriteStream(initial_size), zone_(zone) {
+ // Go ahead and allocate initial space at construction.
+ EnsureSpace(initial_size_);
+ }
+
+ private:
+ virtual void Realloc(intptr_t new_size);
+
+ Zone* const zone_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoneWriteStream);
+};
+
+// A streaming write stream that uses the internal buffer only for non-flushed
+// data. Like MallocWriteStream, uses realloc for reallocation, and flushes and
+// frees the internal buffer when destructed. Since part or all of the written
+// data may be flushed and no longer in the internal buffer, it does not provide
+// a way to retrieve the written contents.
+class StreamingWriteStream : public BaseWriteStream {
public:
explicit StreamingWriteStream(intptr_t initial_capacity,
Dart_StreamingWriteCallback callback,
- void* callback_data);
+ void* callback_data)
+ : BaseWriteStream(initial_capacity),
+ callback_(callback),
+ callback_data_(callback_data) {
+ // Go ahead and allocate initial space at construction.
+ EnsureSpace(initial_capacity);
+ }
~StreamingWriteStream();
- intptr_t position() const { return flushed_size_ + (cursor_ - buffer_); }
-
- void Align(intptr_t alignment) {
- intptr_t padding = Utils::RoundUp(position(), alignment) - position();
- EnsureAvailable(padding);
- memset(cursor_, 0, padding);
- cursor_ += padding;
- }
-
- void Print(const char* format, ...) {
- va_list args;
- va_start(args, format);
- VPrint(format, args);
- va_end(args);
- }
- void VPrint(const char* format, va_list args);
-
- void WriteBytes(const uint8_t* buffer, intptr_t size) {
- EnsureAvailable(size);
- if (size != 0) {
- memmove(cursor_, buffer, size);
- }
- cursor_ += size;
- }
-
private:
- void EnsureAvailable(intptr_t needed) {
- intptr_t available = limit_ - cursor_;
- if (available >= needed) return;
- EnsureAvailableSlowPath(needed);
+ // Flushes any unflushed data to callback_data and resets the internal
+ // buffer. Changes current_ and flushed_size_ accordingly.
+ virtual void Flush();
+
+ virtual void Realloc(intptr_t new_size);
+
+ virtual intptr_t Position() const {
+ return flushed_size_ + BaseWriteStream::Position();
}
- void EnsureAvailableSlowPath(intptr_t needed);
- void Flush();
+ virtual void SetPosition(intptr_t value) {
+ // Make sure we're not trying to set the position to already-flushed data.
+ ASSERT(value >= flushed_size_);
+ BaseWriteStream::SetPosition(value - flushed_size_);
+ }
- uint8_t* buffer_;
- uint8_t* cursor_;
- uint8_t* limit_;
- intptr_t flushed_size_;
- Dart_StreamingWriteCallback callback_;
- void* callback_data_;
+ const Dart_StreamingWriteCallback callback_;
+ void* const callback_data_;
+ intptr_t flushed_size_ = 0;
DISALLOW_COPY_AND_ASSIGN(StreamingWriteStream);
};
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 360929b..f194067 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -1231,12 +1231,6 @@
return -1;
}
-static uint8_t* ZoneReAlloc(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- return Thread::Current()->zone()->Realloc<uint8_t>(ptr, old_size, new_size);
-}
-
TypedDataPtr DeoptInfoBuilder::CreateDeoptInfo(const Array& deopt_table) {
intptr_t length = instructions_.length();
@@ -1260,9 +1254,8 @@
length -= (suffix_length - 1);
}
- uint8_t* buffer;
- typedef WriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
- WriteStream stream(&buffer, ZoneReAlloc, 2 * length * kWordSize);
+ typedef ZoneWriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
+ ZoneWriteStream stream(zone(), 2 * length * kWordSize);
Writer::Write(&stream, FrameSize());
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 606ef61..9d08ce5 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -14,14 +14,14 @@
namespace dart {
-// A wrapper around StreamingWriteStream that provides methods useful for
+// A wrapper around BaseWriteStream that provides methods useful for
// writing ELF files (e.g., using ELF definitions of data sizes).
class ElfWriteStream : public ValueObject {
public:
- explicit ElfWriteStream(StreamingWriteStream* stream)
+ explicit ElfWriteStream(BaseWriteStream* stream)
: stream_(ASSERT_NOTNULL(stream)) {}
- intptr_t position() const { return stream_->position(); }
+ intptr_t position() const { return stream_->Position(); }
void Align(const intptr_t alignment) {
ASSERT(Utils::IsPowerOfTwo(alignment));
stream_->Align(alignment);
@@ -51,7 +51,7 @@
#endif
private:
- StreamingWriteStream* const stream_;
+ BaseWriteStream* const stream_;
};
static constexpr intptr_t kLinearInitValue = -1;
@@ -127,7 +127,7 @@
FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
// Each section belongs to at most one PT_LOAD segment.
- const Segment* load_segment = nullptr;
+ Segment* load_segment = nullptr;
virtual intptr_t MemorySize() const = 0;
@@ -234,6 +234,9 @@
// a memory offset since we use it to determine the segment memory offset.
ASSERT(initial_section->IsAllocated());
ASSERT(initial_section->memory_offset_is_set());
+ // Make sure the memory offset chosen for the initial section is consistent
+ // with the alignment for the segment.
+ ASSERT(Utils::IsAligned(initial_section->memory_offset(), Alignment(type)));
sections_.Add(initial_section);
if (type == elf::ProgramHeaderType::PT_LOAD) {
ASSERT(initial_section->load_segment == nullptr);
@@ -245,6 +248,7 @@
static intptr_t Alignment(elf::ProgramHeaderType segment_type) {
switch (segment_type) {
+ case elf::ProgramHeaderType::PT_PHDR:
case elf::ProgramHeaderType::PT_DYNAMIC:
return compiler::target::kWordSize;
case elf::ProgramHeaderType::PT_NOTE:
@@ -319,6 +323,30 @@
return true;
}
+ void Replace(Section* old_section, Section* new_section) {
+ ASSERT(old_section->load_segment == this);
+ // All these must be true for replacement to be safe.
+ ASSERT_EQUAL(static_cast<uint32_t>(old_section->type),
+ static_cast<uint32_t>(new_section->type));
+ ASSERT_EQUAL(old_section->MemorySize(), new_section->MemorySize());
+ ASSERT_EQUAL(old_section->IsExecutable(), new_section->IsExecutable());
+ ASSERT_EQUAL(old_section->IsWritable(), new_section->IsWritable());
+ ASSERT(old_section->memory_offset_is_set());
+ ASSERT(!new_section->memory_offset_is_set());
+ for (intptr_t i = 0; i < sections_.length(); i++) {
+ auto const section = sections_[i];
+ if (section != old_section) {
+ continue;
+ }
+ new_section->set_memory_offset(old_section->memory_offset());
+ sections_[i] = new_section;
+ new_section->load_segment = this;
+ old_section->load_segment = nullptr;
+ return;
+ }
+ UNREACHABLE();
+ }
+
intptr_t FileOffset() const { return sections_[0]->file_offset(); }
intptr_t FileSize() const {
@@ -792,6 +820,7 @@
}
};
+// We assume that the final program table fits in a single page of memory.
static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
// Here, both VM and isolate will be compiled into a single snapshot.
@@ -806,7 +835,7 @@
static const intptr_t kBssSize =
kBssIsolateOffset + BSS::kIsolateEntryCount * compiler::target::kWordSize;
-Elf::Elf(Zone* zone, StreamingWriteStream* stream, Type type, Dwarf* dwarf)
+Elf::Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf)
: zone_(zone),
unwrapped_stream_(stream),
type_(type),
@@ -818,7 +847,7 @@
// Separate debugging information should always have a Dwarf object.
ASSERT(type_ == Type::Snapshot || dwarf_ != nullptr);
// Assumed by various offset logic in this file.
- ASSERT_EQUAL(unwrapped_stream_->position(), 0);
+ ASSERT_EQUAL(unwrapped_stream_->Position(), 0);
// The first section in the section header table is always a reserved
// entry containing only 0 values.
sections_.Add(new (zone_) ReservedSection());
@@ -834,9 +863,20 @@
auto const start_segment =
new (zone_) ProgramTableLoadSegment(zone_, kProgramTableSegmentSize);
segments_.Add(start_segment);
- // Note that the BSS segment must be the first user-defined segment because
+ // We allocate an initial build ID of all zeroes, since we need the build ID
+ // memory offset during ImageHeader creation (see BlobImageWriter::WriteText).
+ // We replace it with the real build ID during finalization. (We add this
+ // prior to BSS because we make the BuildID section writable also, so they are
+ // placed in the same segment before any non-writable ones, and if we add it
+ // after, then in separate debugging information, it'll go into a separate
+ // segment because the BSS section for debugging info is NOBITS.)
+ build_id_ = GenerateBuildId();
+ AddSection(build_id_, kBuildIdNoteName, kSnapshotBuildIdAsmSymbol);
+ // Note that the BSS segment must be in the first user-defined segment because
// it cannot be placed in between any two non-writable segments, due to a bug
- // in Jelly Bean's ELF loader. See also Elf::WriteProgramTable().
+ // in Jelly Bean's ELF loader. (For this reason, the program table segments
+ // generated during finalization are marked as writable.) See also
+ // Elf::WriteProgramTable().
//
// We add it in all cases, even to the separate debugging information ELF,
// to ensure that relocated addresses are consistent between ELF snapshots
@@ -844,8 +884,14 @@
AddSection(bss_, ".bss", kSnapshotBssAsmSymbol);
}
-intptr_t Elf::NextMemoryOffset() const {
- return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), Elf::kPageSize);
+intptr_t Elf::NextMemoryOffset(intptr_t alignment) const {
+ // Without more information, we won't know whether we might create a new
+ // segment or put the section into the current one. Thus, for now, only allow
+ // the offset to be queried ahead of time if it matches the load segment
+ // alignment.
+ auto const type = elf::ProgramHeaderType::PT_LOAD;
+ ASSERT_EQUAL(alignment, Segment::Alignment(type));
+ return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), alignment);
}
uword Elf::BssStart(bool vm) const {
@@ -870,8 +916,10 @@
// We can't add this section to the last load segment, so create a new one.
// The new segment starts at the next aligned address.
auto const type = elf::ProgramHeaderType::PT_LOAD;
+ intptr_t alignment =
+ Utils::Maximum(section->alignment, Segment::Alignment(type));
auto const start_address =
- Utils::RoundUp(last_load->MemoryEnd(), Segment::Alignment(type));
+ Utils::RoundUp(last_load->MemoryEnd(), alignment);
section->set_memory_offset(start_address);
auto const segment = new (zone_) Segment(zone_, section, type);
segments_.Add(segment);
@@ -882,13 +930,31 @@
return section->memory_offset();
}
+void Elf::ReplaceSection(Section* old_section, Section* new_section) {
+ ASSERT(section_table_file_size_ < 0);
+ ASSERT(old_section->index_is_set());
+ ASSERT(!new_section->index_is_set());
+ ASSERT_EQUAL(new_section->IsAllocated(), old_section->IsAllocated());
+ new_section->set_name(old_section->name());
+ new_section->set_index(old_section->index());
+ sections_[old_section->index()] = new_section;
+
+ if (!old_section->IsAllocated()) {
+ return;
+ }
+
+ ASSERT(program_table_file_size_ < 0);
+ ASSERT(old_section->load_segment != nullptr);
+ old_section->load_segment->Replace(old_section, new_section);
+}
+
intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
// When making a separate debugging info file for assembly, we don't have
// the binary text segment contents.
ASSERT(type_ == Type::DebugInfo || bytes != nullptr);
- auto const image = new (zone_)
- BitsContainer(type_, /*executable=*/true,
- /*writable=*/false, size, bytes, Elf::kPageSize);
+ auto const image = new (zone_) BitsContainer(type_, /*executable=*/true,
+ /*writable=*/false, size, bytes,
+ ImageWriter::kTextAlignment);
return AddSection(image, ".text", name);
}
@@ -904,14 +970,14 @@
memset(bytes, 0, size);
}
return new (zone) BitsContainer(type, /*executable=*/false, /*writable=*/true,
- kBssSize, bytes, Image::kBssAlignment);
+ kBssSize, bytes, ImageWriter::kBssAlignment);
}
intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
ASSERT(bytes != nullptr);
- auto const image = new (zone_)
- BitsContainer(type_, /*executable=*/false,
- /*writable=*/false, size, bytes, kMaxObjectAlignment);
+ auto const image = new (zone_) BitsContainer(type_, /*executable=*/false,
+ /*writable=*/false, size, bytes,
+ ImageWriter::kRODataAlignment);
return AddSection(image, ".rodata", name);
}
@@ -956,9 +1022,9 @@
class DwarfElfStream : public DwarfWriteStream {
public:
explicit DwarfElfStream(Zone* zone,
- WriteStream* stream,
+ NonStreamingWriteStream* stream,
const CStringMap<intptr_t>& address_map)
- : zone_(zone),
+ : zone_(ASSERT_NOTNULL(zone)),
stream_(ASSERT_NOTNULL(stream)),
address_map_(address_map) {}
@@ -1012,8 +1078,11 @@
return fixup;
}
void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
- const uint32_t value = position() - start;
- memmove(stream_->buffer() + fixup, &value, sizeof(value));
+ const intptr_t old_position = position();
+ stream_->SetPosition(fixup);
+ const uint32_t value = old_position - start;
+ stream_->WriteBytes(&value, sizeof(value));
+ stream_->SetPosition(old_position);
}
void OffsetFromSymbol(const char* symbol, intptr_t offset) {
auto const address = address_map_.LookupValue(symbol);
@@ -1053,7 +1122,7 @@
}
Zone* const zone_;
- WriteStream* const stream_;
+ NonStreamingWriteStream* const stream_;
const CStringMap<intptr_t>& address_map_;
uint32_t* abstract_origins_ = nullptr;
intptr_t abstract_origins_size_ = -1;
@@ -1064,10 +1133,6 @@
static constexpr intptr_t kInitialDwarfBufferSize = 64 * KB;
#endif
-static uint8_t* ZoneReallocate(uint8_t* ptr, intptr_t len, intptr_t new_len) {
- return Thread::Current()->zone()->Realloc<uint8_t>(ptr, len, new_len);
-}
-
Segment* Elf::LastLoadSegment() const {
for (intptr_t i = segments_.length() - 1; i >= 0; i--) {
auto const segment = segments_.At(i);
@@ -1155,27 +1220,24 @@
// provide unwinding information.
{
- uint8_t* buffer = nullptr;
- WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
+ ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
dwarf_->WriteAbbreviations(&dwarf_stream);
- AddDebug(".debug_abbrev", buffer, stream.bytes_written());
+ AddDebug(".debug_abbrev", stream.buffer(), stream.bytes_written());
}
{
- uint8_t* buffer = nullptr;
- WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
+ ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
dwarf_->WriteDebugInfo(&dwarf_stream);
- AddDebug(".debug_info", buffer, stream.bytes_written());
+ AddDebug(".debug_info", stream.buffer(), stream.bytes_written());
}
{
- uint8_t* buffer = nullptr;
- WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
+ ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
dwarf_->WriteLineNumberProgram(&dwarf_stream);
- AddDebug(".debug_line", buffer, stream.bytes_written());
+ AddDebug(".debug_line", stream.buffer(), stream.bytes_written());
}
#endif
}
@@ -1189,11 +1251,11 @@
// without changing how we add the .text and .rodata sections (since we
// determine memory offsets for those sections when we add them, and the
// text sections must have the memory offsets to do BSS relocations).
- if (auto const build_id = GenerateBuildId()) {
- AddSection(build_id, ".note.gnu.build-id", kSnapshotBuildIdAsmSymbol);
+ if (auto const new_build_id = GenerateBuildId()) {
+ ReplaceSection(build_id_, new_build_id);
// Add a PT_NOTE segment for the build ID.
- segments_.Add(new (zone_) NoteSegment(zone_, build_id));
+ segments_.Add(new (zone_) NoteSegment(zone_, new_build_id));
}
// Adding the dynamic symbol table and associated sections.
@@ -1291,9 +1353,15 @@
return FinalizeHash(hash, 32);
}
+uword Elf::BuildIdStart(intptr_t* size) {
+ ASSERT(size != nullptr);
+ ASSERT(build_id_ != nullptr);
+ *size = kBuildIdDescriptionLength;
+ return build_id_->memory_offset() + kBuildIdDescriptionOffset;
+}
+
Section* Elf::GenerateBuildId() {
- uint8_t* notes_buffer = nullptr;
- WriteStream stream(¬es_buffer, ZoneReallocate, kBuildIdSize);
+ ZoneWriteStream stream(zone(), kBuildIdSize);
stream.WriteFixed(kBuildIdNameLength);
stream.WriteFixed(kBuildIdDescriptionLength);
stream.WriteFixed(static_cast<uint32_t>(elf::NoteType::NT_GNU_BUILD_ID));
@@ -1319,9 +1387,15 @@
}
ASSERT_EQUAL(stream.bytes_written() - description_start,
kBuildIdDescriptionLength);
- return new (zone_) BitsContainer(
- elf::SectionHeaderType::SHT_NOTE, /*allocate=*/true, /*executable=*/false,
- /*writable=*/false, stream.bytes_written(), notes_buffer, kNoteAlignment);
+ ASSERT_EQUAL(stream.bytes_written(), kBuildIdSize);
+ // While the build ID section does not need to be writable, it and the
+ // BSS section are allocated segments at the same time. Having the same flags
+ // ensures they will be combined in the same segment and not unnecessarily
+ // aligned into a new page.
+ return new (zone_) BitsContainer(elf::SectionHeaderType::SHT_NOTE,
+ /*allocate=*/true, /*executable=*/false,
+ /*writable=*/true, stream.bytes_written(),
+ stream.buffer(), kNoteAlignment);
}
void Elf::FinalizeProgramTable() {
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index da0af3c..37b2fc8 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -30,12 +30,9 @@
DebugInfo,
};
- Elf(Zone* zone,
- StreamingWriteStream* stream,
- Type type,
- Dwarf* dwarf = nullptr);
+ Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf = nullptr);
- static const intptr_t kPageSize = 4096;
+ static constexpr intptr_t kPageSize = 4096;
bool IsStripped() const { return dwarf_ == nullptr; }
@@ -44,13 +41,13 @@
Dwarf* dwarf() { return dwarf_; }
uword BssStart(bool vm) const;
+ uword BuildIdStart(intptr_t* size);
- // What the next memory offset for a kPageSize-aligned section would be.
+ // What the next memory offset for an appropriately aligned section would be.
//
// Only used by BlobImageWriter::WriteText() to determine the memory offset
// for the text section before it is added.
- intptr_t NextMemoryOffset() const;
- intptr_t AddNoBits(const char* name, const uint8_t* bytes, intptr_t size);
+ intptr_t NextMemoryOffset(intptr_t alignment) const;
intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
@@ -58,6 +55,8 @@
void Finalize();
private:
+ static constexpr const char* kBuildIdNoteName = ".note.gnu.build-id";
+
static Section* CreateBSS(Zone* zone, Type type, intptr_t size);
// Adds the section and also creates a PT_LOAD segment for the section if it
@@ -71,6 +70,11 @@
intptr_t AddSection(Section* section,
const char* name,
const char* symbol_name = nullptr);
+ // Replaces [old_section] with [new_section] in all appropriate places. If the
+ // section is allocated, the memory size of the section must be the same as
+ // the original to ensure any already-calculated memory offsets are unchanged.
+ void ReplaceSection(Section* old_section, Section* new_section);
+
void AddStaticSymbol(const char* name,
intptr_t info,
intptr_t section_index,
@@ -97,7 +101,7 @@
void WriteSections(ElfWriteStream* stream);
Zone* const zone_;
- StreamingWriteStream* const unwrapped_stream_;
+ BaseWriteStream* const unwrapped_stream_;
const Type type_;
// If nullptr, then the ELF file should be stripped of static information like
@@ -118,6 +122,12 @@
StringTable* strtab_ = nullptr;
SymbolTable* symtab_ = nullptr;
+ // We always create a GNU build ID for all Elf files. In order to create
+ // the appropriate offset to it in an ImageHeader object, we create an
+ // initial build ID section as a placeholder and then replace that section
+ // during finalization once we have the information to calculate the real one.
+ Section* build_id_;
+
GrowableArray<Section*> sections_;
GrowableArray<Segment*> segments_;
intptr_t memory_offset_;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 3bcb484..142c890 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -384,8 +384,8 @@
}
#if !defined(DART_PRECOMPILED_RUNTIME)
-void CatchEntryMove::WriteTo(WriteStream* stream) {
- using Writer = WriteStream::Raw<sizeof(int32_t), int32_t>;
+void CatchEntryMove::WriteTo(BaseWriteStream* stream) {
+ using Writer = BaseWriteStream::Raw<sizeof(int32_t), int32_t>;
Writer::Write(stream, src_);
Writer::Write(stream, dest_and_kind_);
}
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 7a44cd8..e7b52e5 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -21,7 +21,7 @@
class Instance;
class Integer;
class ReadStream;
-class WriteStream;
+class BaseWriteStream;
class String;
class Thread;
class TypedData;
@@ -203,7 +203,7 @@
static CatchEntryMove ReadFrom(ReadStream* stream);
#if !defined(DART_PRECOMPILED_RUNTIME)
- void WriteTo(WriteStream* stream);
+ void WriteTo(BaseWriteStream* stream);
#endif
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 3d52db5..8ed1d98 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -6,6 +6,7 @@
#include "include/dart_api.h"
#include "platform/assert.h"
+#include "vm/bss_relocs.h"
#include "vm/class_id.h"
#include "vm/compiler/runtime_api.h"
#include "vm/dwarf.h"
@@ -36,10 +37,84 @@
DEFINE_FLAG(charp,
print_instructions_sizes_to,
- NULL,
+ nullptr,
"Print sizes of all instruction objects to the given file");
#endif
+const ImageHeaderLayout* Image::ExtraInfo(const uword raw_memory,
+ const uword size) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ auto const raw_value = FieldValue(raw_memory, HeaderField::ImageHeaderOffset);
+ if (raw_value != kNoImageHeader) {
+ ASSERT(raw_value >= kHeaderSize);
+ ASSERT(raw_value <= size - ImageHeader::InstanceSize());
+ return reinterpret_cast<const ImageHeaderLayout*>(raw_memory + raw_value);
+ }
+#endif
+ return nullptr;
+}
+
+uword* Image::bss() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(extra_info_ != nullptr);
+ // There should always be a non-zero BSS offset.
+ ASSERT(extra_info_->bss_offset_ != 0);
+ // Returning a non-const uword* is safe because we're translating from
+ // the start of the instructions (read-only) to the start of the BSS
+ // (read-write).
+ return reinterpret_cast<uword*>(raw_memory_ + extra_info_->bss_offset_);
+#else
+ return nullptr;
+#endif
+}
+
+uword Image::instructions_relocated_address() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(extra_info_ != nullptr);
+ // For assembly snapshots, we need to retrieve this from the initialized BSS.
+ const uword address =
+ compiled_to_elf() ? extra_info_->instructions_relocated_address_
+ : bss()[BSS::RelocationIndex(
+ BSS::Relocation::InstructionsRelocatedAddress)];
+ ASSERT(address != kNoRelocatedAddress);
+ return address;
+#else
+ return kNoRelocatedAddress;
+#endif
+}
+
+const uint8_t* Image::build_id() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(extra_info_ != nullptr);
+ if (extra_info_->build_id_offset_ != kNoBuildId) {
+ return reinterpret_cast<const uint8_t*>(raw_memory_ +
+ extra_info_->build_id_offset_);
+ }
+#endif
+ return nullptr;
+}
+
+intptr_t Image::build_id_length() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(extra_info_ != nullptr);
+ return extra_info_->build_id_length_;
+#else
+ return 0;
+#endif
+}
+
+bool Image::compiled_to_elf() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ ASSERT(extra_info_ != nullptr);
+ // Since assembly snapshots can't set up this field correctly (instead,
+ // it's initialized in BSS at snapshot load time), we use it to detect
+ // direct-to-ELF snapshots.
+ return extra_info_->instructions_relocated_address_ != kNoRelocatedAddress;
+#else
+ return false;
+#endif
+}
+
intptr_t ObjectOffsetTrait::Hashcode(Key key) {
ObjectPtr obj = key;
ASSERT(!obj->IsSmi());
@@ -88,6 +163,8 @@
next_text_offset_(0),
objects_(),
instructions_(),
+ image_type_(TagObjectTypeAsReadOnly(t->zone(), "Image")),
+ image_header_type_(TagObjectTypeAsReadOnly(t->zone(), "ImageHeader")),
instructions_section_type_(
TagObjectTypeAsReadOnly(t->zone(), "InstructionsSection")),
instructions_type_(TagObjectTypeAsReadOnly(t->zone(), "Instructions")),
@@ -386,7 +463,7 @@
}
#endif
-void ImageWriter::Write(WriteStream* clustered_stream, bool vm) {
+void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Heap* heap = thread->isolate()->heap();
@@ -412,33 +489,36 @@
data.obj_ = &Object::Handle(zone, data.raw_obj_);
}
- // Append the direct-mapped RO data objects after the clustered snapshot.
- // We need to do this before WriteText because WriteText currently adds the
- // finalized contents of the clustered_stream as data sections.
- offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
- : V8SnapshotProfileWriter::kIsolateData;
- WriteROData(clustered_stream);
+ // Needs to happen before WriteText, as we add information about the
+ // BSSsection in the text section as an initial ImageHeader object.
+ WriteBss(vm);
offset_space_ = vm ? V8SnapshotProfileWriter::kVmText
: V8SnapshotProfileWriter::kIsolateText;
- // Needs to happen after WriteROData, because all image writers currently
- // add the clustered data information to their output in WriteText().
- WriteText(clustered_stream, vm);
+ WriteText(vm);
+
+ // Append the direct-mapped RO data objects after the clustered snapshot
+ // and then for ELF and assembly outputs, add appropriate sections with
+ // that combined data.
+ offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
+ : V8SnapshotProfileWriter::kIsolateData;
+ WriteROData(clustered_stream, vm);
}
-void ImageWriter::WriteROData(WriteStream* stream) {
+void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) {
#if defined(DART_PRECOMPILER)
const intptr_t start_position = stream->Position();
#endif
- stream->Align(kMaxObjectAlignment);
+ stream->Align(ImageWriter::kRODataAlignment);
// Heap page starts here.
intptr_t section_start = stream->Position();
stream->WriteWord(next_data_offset_); // Data length.
- // Zero values for other image header fields.
- stream->Align(kMaxObjectAlignment);
+ stream->WriteWord(0); // No ImageHeader object in data sections.
+ // Zero values for the rest of the Image object header bytes.
+ stream->Align(Image::kHeaderSize);
ASSERT(stream->Position() - section_start == Image::kHeaderSize);
#if defined(DART_PRECOMPILER)
if (profile_writer_ != nullptr) {
@@ -539,7 +619,7 @@
#if defined(DART_PRECOMPILER)
class DwarfAssemblyStream : public DwarfWriteStream {
public:
- explicit DwarfAssemblyStream(StreamingWriteStream* stream)
+ explicit DwarfAssemblyStream(BaseWriteStream* stream)
: stream_(ASSERT_NOTNULL(stream)) {}
void sleb128(intptr_t value) { Print(".sleb128 %" Pd "\n", value); }
@@ -648,7 +728,7 @@
#undef FORM_ADDR
- StreamingWriteStream* const stream_;
+ BaseWriteStream* const stream_;
intptr_t temp_ = 0;
DISALLOW_COPY_AND_ASSIGN(DwarfAssemblyStream);
@@ -670,19 +750,18 @@
}
AssemblyImageWriter::AssemblyImageWriter(Thread* thread,
- Dart_StreamingWriteCallback callback,
- void* callback_data,
+ BaseWriteStream* stream,
bool strip,
Elf* debug_elf)
: ImageWriter(thread),
- assembly_stream_(512 * KB, callback, callback_data),
+ assembly_stream_(stream),
assembly_dwarf_(AddDwarfIfUnstripped(thread->zone(), strip, debug_elf)),
debug_elf_(debug_elf) {}
void AssemblyImageWriter::Finalize() {
#if defined(DART_PRECOMPILER)
if (assembly_dwarf_ != nullptr) {
- DwarfAssemblyStream dwarf_stream(&assembly_stream_);
+ DwarfAssemblyStream dwarf_stream(assembly_stream_);
dwarf_stream.AbbreviationsPrologue();
assembly_dwarf_->WriteAbbreviations(&dwarf_stream);
dwarf_stream.DebugInfoPrologue();
@@ -751,7 +830,61 @@
return SnapshotNameFor(index, *data.code_);
}
-void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
+#if defined(DART_PRECOMPILER)
+static const char* const kVmSnapshotBssAsmSymbol = "_kDartVmSnapshotBss";
+static const char* const kIsolateSnapshotBssAsmSymbol =
+ "_kDartIsolateSnapshotBss";
+#endif
+
+void AssemblyImageWriter::WriteBss(bool vm) {
+#if defined(DART_PRECOMPILER)
+ auto const bss_symbol =
+ vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
+ assembly_stream_->Print(".bss\n");
+ // Align the BSS contents as expected by the Image class.
+ Align(ImageWriter::kBssAlignment);
+ assembly_stream_->Print("%s:\n", bss_symbol);
+
+ auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
+ for (intptr_t i = 0; i < entry_count; i++) {
+ WriteWordLiteralText(0);
+ }
+#endif
+}
+
+void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
+ bool vm) {
+ ImageWriter::WriteROData(clustered_stream, vm);
+#if defined(DART_PRECOMPILED_RUNTIME)
+ UNREACHABLE();
+#else
+#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
+ defined(TARGET_OS_FUCHSIA)
+ assembly_stream_->Print(".section .rodata\n");
+#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
+ assembly_stream_->Print(".const\n");
+#else
+ UNIMPLEMENTED();
+#endif
+
+ const char* data_symbol =
+ vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
+ assembly_stream_->Print(".globl %s\n", data_symbol);
+ Align(ImageWriter::kRODataAlignment);
+ assembly_stream_->Print("%s:\n", data_symbol);
+ const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
+ const intptr_t length = clustered_stream->bytes_written();
+ WriteByteSequence(buffer, buffer + length);
+#if defined(DART_PRECOMPILER)
+ if (debug_elf_ != nullptr) {
+ // Add a NoBits section for the ROData as well.
+ debug_elf_->AddROData(data_symbol, clustered_stream->buffer(), length);
+ }
+#endif // defined(DART_PRECOMPILER)
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
+}
+
+void AssemblyImageWriter::WriteText(bool vm) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
@@ -760,25 +893,25 @@
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
-#if defined(DART_PRECOMPILER)
- const char* bss_symbol =
- vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
- intptr_t debug_segment_base = 0;
- if (debug_elf_ != nullptr) {
- debug_segment_base = debug_elf_->NextMemoryOffset();
- }
-#endif
-
const char* instructions_symbol = vm ? kVmSnapshotInstructionsAsmSymbol
: kIsolateSnapshotInstructionsAsmSymbol;
- assembly_stream_.Print(".text\n");
- assembly_stream_.Print(".globl %s\n", instructions_symbol);
+ assembly_stream_->Print(".text\n");
+ assembly_stream_->Print(".globl %s\n", instructions_symbol);
// Start snapshot at page boundary.
- ASSERT(VirtualMemory::PageSize() >= kMaxObjectAlignment);
- ASSERT(VirtualMemory::PageSize() >= Image::kBssAlignment);
- Align(VirtualMemory::PageSize());
- assembly_stream_.Print("%s:\n", instructions_symbol);
+ ASSERT(ImageWriter::kTextAlignment >= VirtualMemory::PageSize());
+ Align(ImageWriter::kTextAlignment);
+ assembly_stream_->Print("%s:\n", instructions_symbol);
+
+#if defined(DART_PRECOMPILER)
+ auto const bss_symbol =
+ vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
+ intptr_t debug_segment_base = 0;
+ if (debug_elf_ != nullptr) {
+ debug_segment_base =
+ debug_elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
+ }
+#endif
intptr_t text_offset = 0;
#if defined(DART_PRECOMPILER)
@@ -793,64 +926,113 @@
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
text_offset += WriteWordLiteralText(image_size);
-
-#if defined(DART_PRECOMPILER)
- assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
- instructions_symbol);
- text_offset += compiler::target::kWordSize;
-#else
- text_offset += WriteWordLiteralText(0); // No relocations.
-#endif
-
- text_offset += Align(kMaxObjectAlignment, text_offset);
- ASSERT_EQUAL(text_offset, Image::kHeaderSize);
-#if defined(DART_PRECOMPILER)
- if (profile_writer_ != nullptr) {
- profile_writer_->SetObjectTypeAndName(parent_id, "Image",
- instructions_symbol);
- // Assign post-instruction padding to the Image, unless we're writing bare
- // instruction payloads, in which case we'll assign it to the
- // InstructionsSection object.
- const intptr_t padding =
- bare_instruction_payloads ? 0 : image_size - next_text_offset_;
- profile_writer_->AttributeBytesTo(parent_id, Image::kHeaderSize + padding);
- profile_writer_->AddRoot(parent_id);
+ if (FLAG_precompiled_mode) {
+ // Output the offset to the ImageHeader object from the start of the image.
+ text_offset += WriteWordLiteralText(Image::kHeaderSize);
+ } else {
+ text_offset += WriteWordLiteralText(Image::kNoImageHeader);
}
-#endif
+ // Zero values for the rest of the Image object header bytes.
+ text_offset += Align(Image::kHeaderSize, text_offset);
+ ASSERT_EQUAL(text_offset, Image::kHeaderSize);
- if (bare_instruction_payloads) {
#if defined(DART_PRECOMPILER)
+ if (FLAG_precompiled_mode) {
+ if (profile_writer_ != nullptr) {
+ profile_writer_->SetObjectTypeAndName(parent_id, image_type_,
+ instructions_symbol);
+ // Assign post-instruction padding to the Image, unless we're writing bare
+ // instruction payloads, in which case we'll assign it to the
+ // InstructionsSection object.
+ const intptr_t padding =
+ bare_instruction_payloads ? 0 : image_size - next_text_offset_;
+ profile_writer_->AttributeBytesTo(parent_id,
+ Image::kHeaderSize + padding);
+ profile_writer_->AddRoot(parent_id);
+ }
+
+ // Write the ImageHeader object, starting with the header.
+ const intptr_t image_header_size =
+ compiler::target::ImageHeader::InstanceSize();
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
- profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+ profile_writer_->SetObjectTypeAndName(id, image_header_type_,
instructions_symbol);
- const intptr_t padding = image_size - next_text_offset_;
- profile_writer_->AttributeBytesTo(
- id, compiler::target::InstructionsSection::HeaderSize() + padding);
+ profile_writer_->AttributeBytesTo(id, image_header_size);
const intptr_t element_offset = id.second - parent_id.second;
profile_writer_->AttributeReferenceTo(
parent_id,
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
- // Later objects will have the InstructionsSection as a parent.
- parent_id = id;
}
-#endif
- const intptr_t section_size = image_size - text_offset;
- // Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
ObjectLayout::OldAndNotMarkedBit::encode(false) |
ObjectLayout::OldAndNotRememberedBit::encode(true) |
ObjectLayout::NewBit::encode(false) |
- ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
- ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
+ ObjectLayout::SizeTag::encode(
+ AdjustObjectSizeForTarget(image_header_size)) |
+ ObjectLayout::ClassIdTag::encode(kImageHeaderCid);
text_offset += WriteWordLiteralText(marked_tags);
- // Calculated using next_text_offset_, which doesn't include post-payload
- // padding to object alignment.
- const intptr_t instructions_length =
- next_text_offset_ - (text_offset + compiler::target::kWordSize);
- text_offset += WriteWordLiteralText(instructions_length);
+
+ // An ImageHeader has four fields:
+ // 1) The BSS offset from this section.
+ assembly_stream_->Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
+ instructions_symbol);
+ text_offset += compiler::target::kWordSize;
+ // 2) The relocated address of the instructions.
+ //
+ // For assembly snapshots, we can't generate assembly to get the absolute
+ // address of the text section, as using the section symbol gives us a
+ // relative offset from the section start, which is 0. Instead, depend on
+ // the BSS initialization to retrieve this for us at runtime. As a side
+ // effect, this field also doubles as a way to detect whether we compiled to
+ // assembly or directly to ELF.
+ text_offset += WriteWordLiteralText(Image::kNoRelocatedAddress);
+ // TODO(dartbug.com/43274): Change once we generate consistent build IDs
+ // between assembly snapshots and their debugging information.
+ // 3) The GNU build ID offset from this section.
+ text_offset += WriteWordLiteralText(Image::kNoBuildId);
+ // 4) The GNU build ID length.
+ text_offset += WriteWordLiteralText(0);
+ text_offset +=
+ Align(compiler::target::ObjectAlignment::kObjectAlignment, text_offset);
+
+ ASSERT_EQUAL(text_offset, Image::kHeaderSize + image_header_size);
+
+ if (bare_instruction_payloads) {
+ if (profile_writer_ != nullptr) {
+ const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
+ profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+ instructions_symbol);
+ const intptr_t padding = image_size - next_text_offset_;
+ profile_writer_->AttributeBytesTo(
+ id, compiler::target::InstructionsSection::HeaderSize() + padding);
+ const intptr_t element_offset = id.second - parent_id.second;
+ profile_writer_->AttributeReferenceTo(
+ parent_id,
+ {id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
+ // Later objects will have the InstructionsSection as a parent.
+ parent_id = id;
+ }
+ const intptr_t section_size = image_size - text_offset;
+ // Add the RawInstructionsSection header.
+ const compiler::target::uword marked_tags =
+ ObjectLayout::OldBit::encode(true) |
+ ObjectLayout::OldAndNotMarkedBit::encode(false) |
+ ObjectLayout::OldAndNotRememberedBit::encode(true) |
+ ObjectLayout::NewBit::encode(false) |
+ ObjectLayout::SizeTag::encode(
+ AdjustObjectSizeForTarget(section_size)) |
+ ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
+ text_offset += WriteWordLiteralText(marked_tags);
+ // Calculated using next_text_offset_, which doesn't include post-payload
+ // padding to object alignment.
+ const intptr_t instructions_length =
+ next_text_offset_ - (text_offset + compiler::target::kWordSize);
+ text_offset += WriteWordLiteralText(instructions_length);
+ }
}
+#endif
FrameUnwindPrologue();
@@ -932,7 +1114,7 @@
text_offset += sizeof(compiler::target::uword);
WriteWordLiteralText(insns.raw_ptr()->size_and_flags_);
text_offset += sizeof(compiler::target::uword);
-#else // defined(IS_SIMARM_X64)
+#else // defined(IS_SIMARM_X64)
uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
WriteWordLiteralText(marked_tags);
object_start += sizeof(uword);
@@ -951,7 +1133,7 @@
#endif
// 2. Write a label at the entry point.
// Linux's perf uses these labels.
- assembly_stream_.Print("%s:\n", object_name);
+ assembly_stream_->Print("%s:\n", object_name);
{
// 3. Write from the payload start to payload end. For AOT snapshots
@@ -981,8 +1163,8 @@
compiler::target::uword data =
*reinterpret_cast<compiler::target::uword*>(cursor);
if ((cursor - payload_start) == next_reloc_offset) {
- assembly_stream_.Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
- bss_symbol, /*addend=*/data);
+ assembly_stream_->Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
+ bss_symbol, /*addend=*/data);
text_offset += compiler::target::kWordSize;
next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
} else {
@@ -1053,41 +1235,7 @@
// writing the text section.
ASSERT(debug_segment_base2 == debug_segment_base);
}
-
- assembly_stream_.Print(".bss\n");
- // Align the BSS contents as expected by the Image class.
- Align(Image::kBssAlignment);
- assembly_stream_.Print("%s:\n", bss_symbol);
-
- auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
- for (intptr_t i = 0; i < entry_count; i++) {
- WriteWordLiteralText(0);
- }
#endif
-
-#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
- defined(TARGET_OS_FUCHSIA)
- assembly_stream_.Print(".section .rodata\n");
-#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
- assembly_stream_.Print(".const\n");
-#else
- UNIMPLEMENTED();
-#endif
-
- const char* data_symbol =
- vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
- assembly_stream_.Print(".globl %s\n", data_symbol);
- Align(kMaxObjectAlignment);
- assembly_stream_.Print("%s:\n", data_symbol);
- const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
- const intptr_t length = clustered_stream->bytes_written();
- WriteByteSequence(buffer, buffer + length);
-#if defined(DART_PRECOMPILER)
- if (debug_elf_ != nullptr) {
- // Add a NoBits section for the ROData as well.
- debug_elf_->AddROData(data_symbol, clustered_stream->buffer(), length);
- }
-#endif // defined(DART_PRECOMPILER)
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
@@ -1095,12 +1243,12 @@
// Creates DWARF's .debug_frame
// CFI = Call frame information
// CFA = Canonical frame address
- assembly_stream_.Print(".cfi_startproc\n");
+ assembly_stream_->Print(".cfi_startproc\n");
#if defined(TARGET_ARCH_X64)
- assembly_stream_.Print(".cfi_def_cfa rbp, 0\n"); // CFA is fp+0
- assembly_stream_.Print(".cfi_offset rbp, 0\n"); // saved fp is *(CFA+0)
- assembly_stream_.Print(".cfi_offset rip, 8\n"); // saved pc is *(CFA+8)
+ assembly_stream_->Print(".cfi_def_cfa rbp, 0\n"); // CFA is fp+0
+ assembly_stream_->Print(".cfi_offset rbp, 0\n"); // saved fp is *(CFA+0)
+ assembly_stream_->Print(".cfi_offset rip, 8\n"); // saved pc is *(CFA+8)
// saved sp is CFA+16
// Should be ".cfi_value_offset rsp, 16", but requires gcc newer than late
// 2016 and not supported by Android's libunwind.
@@ -1109,14 +1257,14 @@
// uleb128 size of operation 2
// DW_OP_plus_uconst 0x23
// uleb128 addend 16
- assembly_stream_.Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
+ assembly_stream_->Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
#elif defined(TARGET_ARCH_ARM64)
COMPILE_ASSERT(FP == R29);
COMPILE_ASSERT(LR == R30);
- assembly_stream_.Print(".cfi_def_cfa x29, 0\n"); // CFA is fp+0
- assembly_stream_.Print(".cfi_offset x29, 0\n"); // saved fp is *(CFA+0)
- assembly_stream_.Print(".cfi_offset x30, 8\n"); // saved pc is *(CFA+8)
+ assembly_stream_->Print(".cfi_def_cfa x29, 0\n"); // CFA is fp+0
+ assembly_stream_->Print(".cfi_offset x29, 0\n"); // saved fp is *(CFA+0)
+ assembly_stream_->Print(".cfi_offset x30, 8\n"); // saved pc is *(CFA+8)
// saved sp is CFA+16
// Should be ".cfi_value_offset sp, 16", but requires gcc newer than late
// 2016 and not supported by Android's libunwind.
@@ -1125,19 +1273,19 @@
// uleb128 size of operation 2
// DW_OP_plus_uconst 0x23
// uleb128 addend 16
- assembly_stream_.Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
+ assembly_stream_->Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
#elif defined(TARGET_ARCH_ARM)
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
COMPILE_ASSERT(FP == R7);
- assembly_stream_.Print(".cfi_def_cfa r7, 0\n"); // CFA is fp+j0
- assembly_stream_.Print(".cfi_offset r7, 0\n"); // saved fp is *(CFA+0)
+ assembly_stream_->Print(".cfi_def_cfa r7, 0\n"); // CFA is fp+j0
+ assembly_stream_->Print(".cfi_offset r7, 0\n"); // saved fp is *(CFA+0)
#else
COMPILE_ASSERT(FP == R11);
- assembly_stream_.Print(".cfi_def_cfa r11, 0\n"); // CFA is fp+0
- assembly_stream_.Print(".cfi_offset r11, 0\n"); // saved fp is *(CFA+0)
+ assembly_stream_->Print(".cfi_def_cfa r11, 0\n"); // CFA is fp+0
+ assembly_stream_->Print(".cfi_offset r11, 0\n"); // saved fp is *(CFA+0)
#endif
- assembly_stream_.Print(".cfi_offset lr, 4\n"); // saved pc is *(CFA+4)
+ assembly_stream_->Print(".cfi_offset lr, 4\n"); // saved pc is *(CFA+4)
// saved sp is CFA+8
// Should be ".cfi_value_offset sp, 8", but requires gcc newer than late
// 2016 and not supported by Android's libunwind.
@@ -1146,14 +1294,14 @@
// uleb128 size of operation 2
// DW_OP_plus_uconst 0x23
// uleb128 addend 8
- assembly_stream_.Print(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
+ assembly_stream_->Print(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
// libunwind on ARM may use .ARM.exidx instead of .debug_frame
#if !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_MACOS_IOS)
COMPILE_ASSERT(FP == R11);
- assembly_stream_.Print(".fnstart\n");
- assembly_stream_.Print(".save {r11, lr}\n");
- assembly_stream_.Print(".setfp r11, sp, #0\n");
+ assembly_stream_->Print(".fnstart\n");
+ assembly_stream_->Print(".save {r11, lr}\n");
+ assembly_stream_->Print(".setfp r11, sp, #0\n");
#endif
#endif
@@ -1162,10 +1310,10 @@
void AssemblyImageWriter::FrameUnwindEpilogue() {
#if defined(TARGET_ARCH_ARM)
#if !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_MACOS_IOS)
- assembly_stream_.Print(".fnend\n");
+ assembly_stream_->Print(".fnend\n");
#endif
#endif
- assembly_stream_.Print(".cfi_endproc\n");
+ assembly_stream_->Print(".cfi_endproc\n");
}
intptr_t AssemblyImageWriter::WriteByteSequence(uword start, uword end) {
@@ -1179,31 +1327,29 @@
}
if (end != end_of_words) {
auto start_of_rest = reinterpret_cast<const uint8_t*>(end_of_words);
- assembly_stream_.Print(".byte ");
+ assembly_stream_->Print(".byte ");
for (auto cursor = start_of_rest;
cursor < reinterpret_cast<const uint8_t*>(end); cursor++) {
- if (cursor != start_of_rest) assembly_stream_.Print(", ");
- assembly_stream_.Print("0x%0.2" Px "", *cursor);
+ if (cursor != start_of_rest) assembly_stream_->Print(", ");
+ assembly_stream_->Print("0x%0.2" Px "", *cursor);
}
- assembly_stream_.Print("\n");
+ assembly_stream_->Print("\n");
}
return end - start;
}
intptr_t AssemblyImageWriter::Align(intptr_t alignment, uword position) {
const uword next_position = Utils::RoundUp(position, alignment);
- assembly_stream_.Print(".balign %" Pd ", 0\n", alignment);
+ assembly_stream_->Print(".balign %" Pd ", 0\n", alignment);
return next_position - position;
}
BlobImageWriter::BlobImageWriter(Thread* thread,
- uint8_t** instructions_blob_buffer,
- ReAlloc alloc,
- intptr_t initial_size,
+ NonStreamingWriteStream* stream,
Elf* debug_elf,
Elf* elf)
: ImageWriter(thread),
- instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
+ instructions_blob_stream_(ASSERT_NOTNULL(stream)),
elf_(elf),
debug_elf_(debug_elf) {
#if defined(DART_PRECOMPILER)
@@ -1215,12 +1361,41 @@
intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) {
const uword size = end - start;
- instructions_blob_stream_.WriteBytes(reinterpret_cast<const void*>(start),
- size);
+ instructions_blob_stream_->WriteBytes(reinterpret_cast<const void*>(start),
+ size);
return size;
}
-void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
+void BlobImageWriter::WriteBss(bool vm) {
+#if defined(DART_PRECOMPILER)
+ // We don't actually write a BSS segment, it's created as part of the
+ // Elf constructor, but make sure it has an non-zero start.
+ ASSERT(elf_->BssStart(vm) != 0);
+#endif
+}
+
+void BlobImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
+ bool vm) {
+ ImageWriter::WriteROData(clustered_stream, vm);
+#if defined(DART_PRECOMPILER)
+ auto const data_symbol =
+ vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
+ if (elf_ != nullptr) {
+ elf_->AddROData(data_symbol, clustered_stream->buffer(),
+ clustered_stream->bytes_written());
+ }
+ if (debug_elf_ != nullptr) {
+ // To keep memory addresses consistent, we create elf::SHT_NOBITS sections
+ // in the debugging information. We still pass along the buffers because
+ // we'll need the buffer bytes at generation time to calculate the build ID
+ // so it'll match the one in the snapshot.
+ debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
+ clustered_stream->bytes_written());
+ }
+#endif
+}
+
+void BlobImageWriter::WriteText(bool vm) {
const bool bare_instruction_payloads =
FLAG_precompiled_mode && FLAG_use_bare_instructions;
auto const zone = Thread::Current()->zone();
@@ -1230,11 +1405,12 @@
: kIsolateSnapshotInstructionsAsmSymbol;
intptr_t segment_base = 0;
if (elf_ != nullptr) {
- segment_base = elf_->NextMemoryOffset();
+ segment_base = elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
}
intptr_t debug_segment_base = 0;
if (debug_elf_ != nullptr) {
- debug_segment_base = debug_elf_->NextMemoryOffset();
+ debug_segment_base =
+ debug_elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
// If we're also generating an ELF snapshot, we want the virtual addresses
// in it and the separately saved DWARF information to match.
ASSERT(elf_ == nullptr || segment_base == debug_segment_base);
@@ -1253,74 +1429,123 @@
// OldPage.
const intptr_t image_size = Utils::RoundUp(
next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
- instructions_blob_stream_.WriteTargetWord(image_size);
-#if defined(DART_PRECOMPILER)
- // Store the offset of the BSS section from the instructions section here.
- // If not compiling to ELF (and thus no BSS segment), write 0.
- const word bss_offset =
- elf_ != nullptr ? elf_->BssStart(vm) - segment_base : 0;
- ASSERT_EQUAL(Utils::RoundDown(bss_offset, Image::kBssAlignment), bss_offset);
- // Set the lowest bit if we are compiling to ELF.
- const word compiled_to_elf = elf_ != nullptr ? 0x1 : 0x0;
- instructions_blob_stream_.WriteTargetWord(bss_offset | compiled_to_elf);
-#else
- instructions_blob_stream_.WriteTargetWord(0); // No relocations.
-#endif
- instructions_blob_stream_.Align(kMaxObjectAlignment);
- ASSERT_EQUAL(instructions_blob_stream_.Position(), Image::kHeaderSize);
- text_offset += Image::kHeaderSize;
-#if defined(DART_PRECOMPILER)
- if (profile_writer_ != nullptr) {
- profile_writer_->SetObjectTypeAndName(parent_id, "Image",
- instructions_symbol);
- // Assign post-instruction padding to the Image, unless we're writing bare
- // instruction payloads, in which case we'll assign it to the
- // InstructionsSection object.
- const intptr_t padding =
- bare_instruction_payloads ? 0 : image_size - next_text_offset_;
- profile_writer_->AttributeBytesTo(parent_id, Image::kHeaderSize + padding);
- profile_writer_->AddRoot(parent_id);
+ instructions_blob_stream_->WriteTargetWord(image_size);
+ if (FLAG_precompiled_mode) {
+ // Output the offset to the ImageHeader object from the start of the image.
+ instructions_blob_stream_->WriteTargetWord(Image::kHeaderSize);
+ } else {
+ instructions_blob_stream_->WriteTargetWord(0); // No ImageHeader object.
}
-#endif
+ // Zero values for the rest of the Image object header bytes.
+ instructions_blob_stream_->Align(Image::kHeaderSize);
+ ASSERT_EQUAL(instructions_blob_stream_->Position(), Image::kHeaderSize);
+ text_offset += Image::kHeaderSize;
- if (bare_instruction_payloads) {
#if defined(DART_PRECOMPILER)
+ if (FLAG_precompiled_mode) {
+ if (profile_writer_ != nullptr) {
+ profile_writer_->SetObjectTypeAndName(parent_id, image_type_,
+ instructions_symbol);
+ // Assign post-instruction padding to the Image, unless we're writing bare
+ // instruction payloads, in which case we'll assign it to the
+ // InstructionsSection object.
+ const intptr_t padding =
+ bare_instruction_payloads ? 0 : image_size - next_text_offset_;
+ profile_writer_->AttributeBytesTo(parent_id,
+ Image::kHeaderSize + padding);
+ profile_writer_->AddRoot(parent_id);
+ }
+
+ // Write the ImageHeader object, starting with the header.
+ const intptr_t image_header_size =
+ compiler::target::ImageHeader::InstanceSize();
if (profile_writer_ != nullptr) {
const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
- profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+ profile_writer_->SetObjectTypeAndName(id, image_header_type_,
instructions_symbol);
- const intptr_t padding = image_size - next_text_offset_;
- profile_writer_->AttributeBytesTo(
- id, compiler::target::InstructionsSection::HeaderSize() + padding);
+ profile_writer_->AttributeBytesTo(id, image_header_size);
const intptr_t element_offset = id.second - parent_id.second;
profile_writer_->AttributeReferenceTo(
parent_id,
{id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
- // Later objects will have the InstructionsSection as a parent.
- parent_id = id;
}
-#endif
- const intptr_t section_size = image_size - Image::kHeaderSize;
- // Add the RawInstructionsSection header.
const compiler::target::uword marked_tags =
ObjectLayout::OldBit::encode(true) |
ObjectLayout::OldAndNotMarkedBit::encode(false) |
ObjectLayout::OldAndNotRememberedBit::encode(true) |
ObjectLayout::NewBit::encode(false) |
- ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
- ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
- instructions_blob_stream_.WriteTargetWord(marked_tags);
- // Uses next_text_offset_ to avoid any post-payload padding.
- const intptr_t instructions_length =
- next_text_offset_ - Image::kHeaderSize -
- compiler::target::InstructionsSection::HeaderSize();
- instructions_blob_stream_.WriteTargetWord(instructions_length);
- ASSERT_EQUAL(instructions_blob_stream_.Position() - text_offset,
- compiler::target::InstructionsSection::HeaderSize());
- text_offset += compiler::target::InstructionsSection::HeaderSize();
- }
+ ObjectLayout::SizeTag::encode(
+ AdjustObjectSizeForTarget(image_header_size)) |
+ ObjectLayout::ClassIdTag::encode(kImageHeaderCid);
+ instructions_blob_stream_->WriteTargetWord(marked_tags);
- ASSERT_EQUAL(text_offset, instructions_blob_stream_.Position());
+ ASSERT(elf_ != nullptr);
+ // An ImageHeader has four fields:
+ // 1) The BSS offset from this section.
+ const word bss_offset = elf_->BssStart(vm) - segment_base;
+ ASSERT(bss_offset != Image::kNoBssSection);
+ instructions_blob_stream_->WriteTargetWord(bss_offset);
+ // 2) The relocated address of the instructions.
+ //
+ // Since we set this to a non-zero value for ELF snapshots, we also use this
+ // to detect compiled-to-ELF snapshots.
+ ASSERT(segment_base != Image::kNoRelocatedAddress);
+ instructions_blob_stream_->WriteTargetWord(segment_base);
+ // 3) The GNU build ID offset from this section.
+ intptr_t build_id_length = 0;
+ const word build_id_offset =
+ elf_->BuildIdStart(&build_id_length) - segment_base;
+ ASSERT(build_id_offset != Image::kNoBuildId);
+ instructions_blob_stream_->WriteTargetWord(build_id_offset);
+ // 4) The GNU build ID length.
+ ASSERT(build_id_length != 0);
+ instructions_blob_stream_->WriteTargetWord(build_id_length);
+ instructions_blob_stream_->Align(
+ compiler::target::ObjectAlignment::kObjectAlignment);
+
+ ASSERT_EQUAL(instructions_blob_stream_->Position() - text_offset,
+ image_header_size);
+ text_offset += image_header_size;
+
+ if (bare_instruction_payloads) {
+ if (profile_writer_ != nullptr) {
+ const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
+ profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+ instructions_symbol);
+ const intptr_t padding = image_size - next_text_offset_;
+ profile_writer_->AttributeBytesTo(
+ id, compiler::target::InstructionsSection::HeaderSize() + padding);
+ const intptr_t element_offset = id.second - parent_id.second;
+ profile_writer_->AttributeReferenceTo(
+ parent_id,
+ {id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
+ // Later objects will have the InstructionsSection as a parent.
+ parent_id = id;
+ }
+ const intptr_t section_size = image_size - text_offset;
+ // Add the RawInstructionsSection header.
+ const compiler::target::uword marked_tags =
+ ObjectLayout::OldBit::encode(true) |
+ ObjectLayout::OldAndNotMarkedBit::encode(false) |
+ ObjectLayout::OldAndNotRememberedBit::encode(true) |
+ ObjectLayout::NewBit::encode(false) |
+ ObjectLayout::SizeTag::encode(
+ AdjustObjectSizeForTarget(section_size)) |
+ ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
+ instructions_blob_stream_->WriteTargetWord(marked_tags);
+ // Uses next_text_offset_ to avoid any post-payload padding.
+ const intptr_t instructions_length =
+ next_text_offset_ - text_offset -
+ compiler::target::InstructionsSection::HeaderSize();
+ instructions_blob_stream_->WriteTargetWord(instructions_length);
+ ASSERT_EQUAL(instructions_blob_stream_->Position() - text_offset,
+ compiler::target::InstructionsSection::HeaderSize());
+ text_offset += compiler::target::InstructionsSection::HeaderSize();
+ }
+ }
+#endif
+
+ ASSERT_EQUAL(text_offset, instructions_blob_stream_->Position());
#if defined(DART_PRECOMPILER)
auto& descriptors = PcDescriptors::Handle(zone);
@@ -1381,29 +1606,29 @@
#endif
#if defined(IS_SIMARM_X64)
- const intptr_t start_offset = instructions_blob_stream_.bytes_written();
+ const intptr_t start_offset = instructions_blob_stream_->bytes_written();
if (!bare_instruction_payloads) {
const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.raw());
marked_tags = UpdateObjectSizeForTarget(size_in_bytes, marked_tags);
- instructions_blob_stream_.WriteTargetWord(marked_tags);
- instructions_blob_stream_.WriteFixed<uint32_t>(
+ instructions_blob_stream_->WriteTargetWord(marked_tags);
+ instructions_blob_stream_->WriteFixed<uint32_t>(
insns.raw_ptr()->size_and_flags_);
} else {
- ASSERT(Utils::IsAligned(instructions_blob_stream_.Position(),
+ ASSERT(Utils::IsAligned(instructions_blob_stream_->Position(),
kBareInstructionsAlignment));
}
- const intptr_t payload_offset = instructions_blob_stream_.Position();
- instructions_blob_stream_.WriteBytes(
+ const intptr_t payload_offset = instructions_blob_stream_->Position();
+ instructions_blob_stream_->WriteBytes(
reinterpret_cast<const void*>(insns.PayloadStart()), insns.Size());
const intptr_t alignment =
bare_instruction_payloads
? kBareInstructionsAlignment
: compiler::target::ObjectAlignment::kObjectAlignment;
- instructions_blob_stream_.Align(alignment);
- const intptr_t end_offset = instructions_blob_stream_.bytes_written();
+ instructions_blob_stream_->Align(alignment);
+ const intptr_t end_offset = instructions_blob_stream_->bytes_written();
text_offset += (end_offset - start_offset);
-#else // defined(IS_SIMARM_X64)
+#else // defined(IS_SIMARM_X64)
// Only payload is output in AOT snapshots.
const uword header_size =
bare_instruction_payloads
@@ -1413,15 +1638,15 @@
const uword object_end = payload_start + payload_size;
if (!bare_instruction_payloads) {
uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
- instructions_blob_stream_.WriteWord(marked_tags);
+ instructions_blob_stream_->WriteWord(marked_tags);
text_offset += sizeof(uword);
object_start += sizeof(uword);
text_offset += WriteByteSequence(object_start, payload_start);
} else {
- ASSERT(Utils::IsAligned(instructions_blob_stream_.Position(),
+ ASSERT(Utils::IsAligned(instructions_blob_stream_->Position(),
kBareInstructionsAlignment));
}
- const intptr_t payload_offset = instructions_blob_stream_.Position();
+ const intptr_t payload_offset = instructions_blob_stream_->Position();
text_offset += WriteByteSequence(payload_start, object_end);
#endif
@@ -1440,13 +1665,14 @@
// or not after loading.
if (elf_ != nullptr) {
const intptr_t current_stream_position =
- instructions_blob_stream_.Position();
+ instructions_blob_stream_->Position();
descriptors = code.pc_descriptors();
PcDescriptors::Iterator iterator(
descriptors, /*kind_mask=*/PcDescriptorsLayout::kBSSRelocation);
+ const intptr_t bss_offset = elf_->BssStart(vm) - segment_base;
while (iterator.MoveNext()) {
const intptr_t reloc_offset = iterator.PcOffset();
@@ -1460,14 +1686,14 @@
// offset of the BSS segment from the relocation position plus the
// addend in the relocation.
auto const reloc_pos = payload_offset + reloc_offset;
- instructions_blob_stream_.SetPosition(reloc_pos);
+ instructions_blob_stream_->SetPosition(reloc_pos);
const compiler::target::word offset = bss_offset - reloc_pos + addend;
- instructions_blob_stream_.WriteTargetWord(offset);
+ instructions_blob_stream_->WriteTargetWord(offset);
}
// Restore stream position after the relocation was patched.
- instructions_blob_stream_.SetPosition(current_stream_position);
+ instructions_blob_stream_->SetPosition(current_stream_position);
}
#else
USE(payload_offset);
@@ -1480,25 +1706,20 @@
// Should be a no-op unless writing bare instruction payloads, in which case
// we need to add post-payload padding to the object alignment. The alignment
// should match the alignment used in image_size above.
- instructions_blob_stream_.Align(
+ instructions_blob_stream_->Align(
compiler::target::ObjectAlignment::kObjectAlignment);
text_offset = Utils::RoundUp(
text_offset, compiler::target::ObjectAlignment::kObjectAlignment);
- ASSERT_EQUAL(text_offset, instructions_blob_stream_.bytes_written());
+ ASSERT_EQUAL(text_offset, instructions_blob_stream_->bytes_written());
ASSERT_EQUAL(text_offset, image_size);
-#ifdef DART_PRECOMPILER
- auto const data_symbol =
- vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
+#if defined(DART_PRECOMPILER)
if (elf_ != nullptr) {
auto const segment_base2 =
- elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
- instructions_blob_stream_.bytes_written());
+ elf_->AddText(instructions_symbol, instructions_blob_stream_->buffer(),
+ instructions_blob_stream_->bytes_written());
ASSERT_EQUAL(segment_base2, segment_base);
- // Write the .rodata section here like the AssemblyImageWriter.
- elf_->AddROData(data_symbol, clustered_stream->buffer(),
- clustered_stream->bytes_written());
}
if (debug_elf_ != nullptr) {
// To keep memory addresses consistent, we create elf::SHT_NOBITS sections
@@ -1506,11 +1727,9 @@
// we'll need the buffer bytes at generation time to calculate the build ID
// so it'll match the one in the snapshot.
auto const debug_segment_base2 = debug_elf_->AddText(
- instructions_symbol, instructions_blob_stream_.buffer(),
- instructions_blob_stream_.bytes_written());
+ instructions_symbol, instructions_blob_stream_->buffer(),
+ instructions_blob_stream_->bytes_written());
ASSERT_EQUAL(debug_segment_base2, debug_segment_base);
- debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
- clustered_stream->bytes_written());
}
#endif
}
@@ -1518,10 +1737,8 @@
ImageReader::ImageReader(const uint8_t* data_image,
const uint8_t* instructions_image)
- : data_image_(data_image), instructions_image_(instructions_image) {
- ASSERT(data_image != NULL);
- ASSERT(instructions_image != NULL);
-}
+ : data_image_(ASSERT_NOTNULL(data_image)),
+ instructions_image_(ASSERT_NOTNULL(instructions_image)) {}
ApiErrorPtr ImageReader::VerifyAlignment() const {
if (!Utils::IsAligned(data_image_, kObjectAlignment) ||
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 6727ca0..a75871b 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -13,6 +13,7 @@
#include "vm/allocation.h"
#include "vm/compiler/runtime_api.h"
#include "vm/datastream.h"
+#include "vm/elf.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/hash_map.h"
@@ -26,65 +27,117 @@
// Forward declarations.
class Code;
class Dwarf;
-class Elf;
class Instructions;
class Object;
class Image : ValueObject {
public:
- explicit Image(const void* raw_memory) : raw_memory_(raw_memory) {
+ explicit Image(const void* raw_memory)
+ : Image(reinterpret_cast<uword>(raw_memory)) {}
+ explicit Image(const uword raw_memory)
+ : raw_memory_(raw_memory),
+ snapshot_size_(FieldValue(raw_memory, HeaderField::ImageSize)),
+ extra_info_(ExtraInfo(raw_memory_, snapshot_size_)) {
ASSERT(Utils::IsAligned(raw_memory, kMaxObjectAlignment));
}
+ // Even though an Image is read-only memory, we must return a void* here.
+ // All objects in an Image are pre-marked, though, so the GC will not attempt
+ // to change the returned memory.
void* object_start() const {
- return reinterpret_cast<void*>(reinterpret_cast<uword>(raw_memory_) +
- kHeaderSize);
+ return reinterpret_cast<void*>(raw_memory_ + kHeaderSize);
}
- uword object_size() const {
- uword snapshot_size = *reinterpret_cast<const uword*>(raw_memory_);
- return snapshot_size - kHeaderSize;
- }
+ uword object_size() const { return snapshot_size_ - kHeaderSize; }
bool contains(uword address) const {
uword start = reinterpret_cast<uword>(object_start());
return address >= start && (address - start < object_size());
}
- // Returns the offset of the BSS section from this image. Only has meaning for
- // instructions images.
- word bss_offset() const {
- auto const raw_value = *(reinterpret_cast<const word*>(raw_memory_) + 1);
- return Utils::RoundDown(raw_value, kBssAlignment);
- }
+ // Returns the address of the BSS section, or nullptr if one is not available.
+ // Only has meaning for instructions images from precompiled snapshots.
+ uword* bss() const;
- // Returns true if the image was compiled directly to ELF. Only has meaning
- // for instructions images.
- bool compiled_to_elf() const {
- auto const raw_value = *(reinterpret_cast<const word*>(raw_memory_) + 1);
- return (raw_value & 0x1) == 0x1;
- }
+ // Returns the relocated address of the isolate's instructions, or 0 if
+ // one is not available. Only has meaning for instructions images from
+ // precompiled snapshots.
+ uword instructions_relocated_address() const;
+
+ // Returns the GNU build ID, or nullptr if not available. See
+ // build_id_length() for the length of the returned buffer. Only has meaning
+ // for instructions images from precompiled snapshots.
+ const uint8_t* build_id() const;
+
+ // Returns the length of the GNU build ID returned by build_id(). Only has
+ // meaning for instructions images from precompiled snapshots.
+ intptr_t build_id_length() const;
+
+ // Returns whether this instructions section was compiled to ELF. Only has
+ // meaning for instructions images from precompiled snapshots.
+ bool compiled_to_elf() const;
private:
- static constexpr intptr_t kHeaderFields = 2;
+ // Word-sized fields in an Image object header.
+ enum class HeaderField : intptr_t {
+ // The size of the image (total of header and payload).
+ ImageSize,
+ // The offset of the ImageHeader object in the image. Note this offset
+ // is from the start of the _image_, _not_ from its payload start, so we
+ // can detect images without ImageHeaders by a 0 value here.
+ ImageHeaderOffset,
+ // If adding more fields, updating kHeaderFields below. (However, more
+ // fields _can't_ be added on 64-bit architectures, see the restrictions
+ // on kHeaderSize below.)
+ };
+
+ // Number of fields described by the HeaderField enum.
+ static constexpr intptr_t kHeaderFields =
+ static_cast<intptr_t>(HeaderField::ImageHeaderOffset) + 1;
+
+ static uword FieldValue(uword raw_memory, HeaderField field) {
+ return reinterpret_cast<const uword*>(
+ raw_memory)[static_cast<intptr_t>(field)];
+ }
+
+ // Constants used to denote special values for the offsets in the Image
+ // object header and the fields of the ImageHeader object.
+ static constexpr intptr_t kNoImageHeader = 0;
+ static constexpr intptr_t kNoBssSection = 0;
+ static constexpr intptr_t kNoRelocatedAddress = 0;
+ static constexpr intptr_t kNoBuildId = 0;
+
+ // The size of the Image object header.
+ //
+ // Note: Image::kHeaderSize is _not_ an architecture-dependent constant,
+ // and so there is no compiler::target::Image::kHeaderSize.
static constexpr intptr_t kHeaderSize = kMaxObjectAlignment;
// Explicitly double-checking kHeaderSize is never changed. Increasing the
// Image header size would mean objects would not start at a place expected
// by parts of the VM (like the GC) that use Image pages as HeapPages.
static_assert(kHeaderSize == kMaxObjectAlignment,
"Image page cannot be used as HeapPage");
+ // Make sure that the number of fields in the Image header fit both on the
+ // host and target architectures.
+ static_assert(kHeaderFields * kWordSize <= kHeaderSize,
+ "Too many fields in Image header for host architecture");
+ static_assert(kHeaderFields * compiler::target::kWordSize <= kHeaderSize,
+ "Too many fields in Image header for target architecture");
- // Determines how many bits we have for encoding any extra information in
- // the BSS offset.
- static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
+ // We don't use a handle or the tagged pointer because this object cannot be
+ // moved in memory by the GC.
+ static const ImageHeaderLayout* ExtraInfo(const uword raw_memory,
+ const uword size);
- const void* raw_memory_; // The symbol kInstructionsSnapshot.
+ // Most internal uses would cast this to uword, so just store it as such.
+ const uword raw_memory_;
+ const intptr_t snapshot_size_;
+ const ImageHeaderLayout* const extra_info_;
// For access to private constants.
friend class AssemblyImageWriter;
friend class BlobImageWriter;
friend class ImageWriter;
- friend class Elf;
DISALLOW_COPY_AND_ASSIGN(Image);
};
@@ -178,12 +231,35 @@
explicit ImageWriter(Thread* thread);
virtual ~ImageWriter() {}
+ // Alignment constants used in writing ELF or assembly snapshots.
+
+ // BSS sections contain word-sized data.
+ static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
+ // ROData sections contain objects wrapped in an Image object.
+ static constexpr intptr_t kRODataAlignment = kMaxObjectAlignment;
+ // Text sections contain objects (even in bare instructions mode) wrapped
+ // in an Image object, and for now we also align them to the same page
+ // size assumed by Elf objects.
+ static_assert(Elf::kPageSize >= kMaxObjectAlignment,
+ "Page alignment must be consistent with max object alignment");
+ static constexpr intptr_t kTextAlignment = Elf::kPageSize;
+
void ResetOffsets() {
next_data_offset_ = Image::kHeaderSize;
next_text_offset_ = Image::kHeaderSize;
- if (FLAG_use_bare_instructions && FLAG_precompiled_mode) {
- next_text_offset_ += compiler::target::InstructionsSection::HeaderSize();
+#if defined(DART_PRECOMPILER)
+ if (FLAG_precompiled_mode) {
+ // We reserve space for the initial ImageHeader object. It is manually
+ // serialized since it involves offsets to other parts of the snapshot.
+ next_text_offset_ += compiler::target::ImageHeader::InstanceSize();
+ if (FLAG_use_bare_instructions) {
+ // For bare instructions mode, we wrap all the instruction payloads
+ // in a single InstructionsSection object.
+ next_text_offset_ +=
+ compiler::target::InstructionsSection::HeaderSize();
+ }
}
+#endif
objects_.Clear();
instructions_.Clear();
}
@@ -201,7 +277,7 @@
int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code);
uint32_t GetDataOffsetFor(ObjectPtr raw_object);
- void Write(WriteStream* clustered_stream, bool vm);
+ void Write(NonStreamingWriteStream* clustered_stream, bool vm);
intptr_t data_size() const { return next_data_offset_; }
intptr_t text_size() const { return next_text_offset_; }
intptr_t GetTextObjectCount() const;
@@ -254,8 +330,9 @@
static const char* TagObjectTypeAsReadOnly(Zone* zone, const char* type);
protected:
- void WriteROData(WriteStream* stream);
- virtual void WriteText(WriteStream* clustered_stream, bool vm) = 0;
+ virtual void WriteBss(bool vm) = 0;
+ virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
+ virtual void WriteText(bool vm) = 0;
void DumpInstructionStats();
void DumpInstructionsSizes();
@@ -309,6 +386,8 @@
V8SnapshotProfileWriter::IdSpace offset_space_ =
V8SnapshotProfileWriter::kSnapshot;
V8SnapshotProfileWriter* profile_writer_ = nullptr;
+ const char* const image_type_;
+ const char* const image_header_type_;
const char* const instructions_section_type_;
const char* const instructions_type_;
const char* const trampoline_type_;
@@ -337,14 +416,13 @@
stream_(ASSERT_NOTNULL(stream)),
section_offset_(section_offset),
start_offset_(stream_->Position() - section_offset),
- object_(object) {}
+ object_type_(writer->ObjectTypeForProfile(object)) {}
~TraceImageObjectScope() {
if (writer_->profile_writer_ == nullptr) return;
ASSERT(writer_->IsROSpace());
writer_->profile_writer_->SetObjectTypeAndName(
- {writer_->offset_space_, start_offset_},
- writer_->ObjectTypeForProfile(object_), nullptr);
+ {writer_->offset_space_, start_offset_}, object_type_, nullptr);
writer_->profile_writer_->AttributeBytesTo(
{writer_->offset_space_, start_offset_},
stream_->Position() - section_offset_ - start_offset_);
@@ -355,7 +433,7 @@
const T* const stream_;
const intptr_t section_offset_;
const intptr_t start_offset_;
- const Object& object_;
+ const char* const object_type_;
};
class SnapshotTextObjectNamer {
@@ -385,15 +463,16 @@
class AssemblyImageWriter : public ImageWriter {
public:
AssemblyImageWriter(Thread* thread,
- Dart_StreamingWriteCallback callback,
- void* callback_data,
+ BaseWriteStream* stream,
bool strip = false,
Elf* debug_elf = nullptr);
void Finalize();
- virtual void WriteText(WriteStream* clustered_stream, bool vm);
-
private:
+ virtual void WriteBss(bool vm);
+ virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
+ virtual void WriteText(bool vm);
+
void FrameUnwindPrologue();
void FrameUnwindEpilogue();
intptr_t WriteByteSequence(uword start, uword end);
@@ -408,16 +487,16 @@
intptr_t WriteWordLiteralText(compiler::target::uword value) {
// Padding is helpful for comparing the .S with --disassemble.
#if defined(TARGET_ARCH_IS_64_BIT)
- assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
+ assembly_stream_->Print(".quad 0x%0.16" Px "\n", value);
#else
- assembly_stream_.Print(".long 0x%0.8" Px "\n", value);
+ assembly_stream_->Print(".long 0x%0.8" Px "\n", value);
#endif
return compiler::target::kWordSize;
}
- StreamingWriteStream assembly_stream_;
- Dwarf* assembly_dwarf_;
- Elf* debug_elf_;
+ BaseWriteStream* const assembly_stream_;
+ Dwarf* const assembly_dwarf_;
+ Elf* const debug_elf_;
DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
};
@@ -425,22 +504,22 @@
class BlobImageWriter : public ImageWriter {
public:
BlobImageWriter(Thread* thread,
- uint8_t** instructions_blob_buffer,
- ReAlloc alloc,
- intptr_t initial_size,
+ NonStreamingWriteStream* stream,
Elf* debug_elf = nullptr,
Elf* elf = nullptr);
- virtual void WriteText(WriteStream* clustered_stream, bool vm);
-
intptr_t InstructionsBlobSize() const {
- return instructions_blob_stream_.bytes_written();
+ return instructions_blob_stream_->bytes_written();
}
private:
+ virtual void WriteBss(bool vm);
+ virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
+ virtual void WriteText(bool vm);
+
intptr_t WriteByteSequence(uword start, uword end);
- WriteStream instructions_blob_stream_;
+ NonStreamingWriteStream* instructions_blob_stream_;
Elf* const elf_;
Elf* const debug_elf_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 119901a..e835735 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13,6 +13,7 @@
#include "platform/unicode.h"
#include "vm/bit_vector.h"
#include "vm/bootstrap.h"
+#include "vm/canonical_tables.h"
#include "vm/class_finalizer.h"
#include "vm/code_comments.h"
#include "vm/code_descriptors.h"
@@ -57,7 +58,6 @@
#include "vm/tags.h"
#include "vm/thread_registry.h"
#include "vm/timeline.h"
-#include "vm/type_table.h"
#include "vm/type_testing_stubs.h"
#include "vm/zone_text_buffer.h"
@@ -16051,6 +16051,10 @@
}
#endif
+const char* ImageHeader::ToCString() const {
+ return "ImageHeader";
+}
+
const char* WeakSerializationReference::ToCString() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return Symbols::OptimizedOut().ToCString();
@@ -24400,8 +24404,7 @@
static void PrintNonSymbolicStackFrameBody(BaseTextBuffer* buffer,
uword call_addr,
uword isolate_instructions,
- uword vm_instructions,
- uword isolate_relocated_address) {
+ uword vm_instructions) {
const Image vm_image(reinterpret_cast<const void*>(vm_instructions));
const Image isolate_image(
reinterpret_cast<const void*>(isolate_instructions));
@@ -24412,7 +24415,9 @@
// Only print the relocated address of the call when we know the saved
// debugging information (if any) will have the same relocated address.
if (isolate_image.compiled_to_elf()) {
- buffer->Printf(" virt %" Pp "", isolate_relocated_address + offset);
+ const uword relocated_section_start =
+ isolate_image.instructions_relocated_address();
+ buffer->Printf(" virt %" Pp "", relocated_section_start + offset);
}
buffer->Printf(" %s+0x%" Px "", symbol_name, offset);
} else if (vm_image.contains(call_addr)) {
@@ -24484,16 +24489,6 @@
PrintSymbolicStackFrameBody(buffer, function_name, url, line, column);
}
-// Find the relocated base of the given instructions section.
-uword InstructionsRelocatedAddress(uword instructions_start) {
- Image image(reinterpret_cast<const uint8_t*>(instructions_start));
- auto const bss_start =
- reinterpret_cast<const uword*>(instructions_start + image.bss_offset());
- auto const index =
- BSS::RelocationIndex(BSS::Relocation::InstructionsRelocatedAddress);
- return bss_start[index];
-}
-
const char* StackTrace::ToCString() const {
auto const T = Thread::Current();
auto const zone = T->zone();
@@ -24512,11 +24507,15 @@
T->isolate_group()->source()->snapshot_instructions);
auto const vm_instructions = reinterpret_cast<uword>(
Dart::vm_isolate()->group()->source()->snapshot_instructions);
- auto const vm_relocated_address =
- InstructionsRelocatedAddress(vm_instructions);
- auto const isolate_relocated_address =
- InstructionsRelocatedAddress(isolate_instructions);
if (FLAG_dwarf_stack_traces_mode) {
+ const Image isolate_instructions_image(
+ reinterpret_cast<const void*>(isolate_instructions));
+ const Image vm_instructions_image(
+ reinterpret_cast<const void*>(vm_instructions));
+ auto const isolate_relocated_address =
+ isolate_instructions_image.instructions_relocated_address();
+ auto const vm_relocated_address =
+ vm_instructions_image.instructions_relocated_address();
// The Dart standard requires the output of StackTrace.toString to include
// all pending activations with precise source locations (i.e., to expand
// inlined frames and provide line and column numbers).
@@ -24530,6 +24529,14 @@
OSThread* thread = OSThread::Current();
buffer.Printf("pid: %" Pd ", tid: %" Pd ", name %s\n", OS::ProcessId(),
OSThread::ThreadIdToIntPtr(thread->id()), thread->name());
+ if (auto const build_id = isolate_instructions_image.build_id()) {
+ const intptr_t length = isolate_instructions_image.build_id_length();
+ buffer.Printf("build_id: '");
+ for (intptr_t i = 0; i < length; i++) {
+ buffer.Printf("%02.2x", build_id[i]);
+ }
+ buffer.Printf("'\n");
+ }
// Print the dso_base of the VM and isolate_instructions. We print both here
// as the VM and isolate may be loaded from different snapshot images.
buffer.Printf("isolate_dso_base: %" Px "",
@@ -24591,8 +24598,7 @@
// prints call addresses instead of return addresses.
buffer.Printf(" #%02" Pd " abs %" Pp "", frame_index, call_addr);
PrintNonSymbolicStackFrameBody(
- &buffer, call_addr, isolate_instructions, vm_instructions,
- isolate_relocated_address);
+ &buffer, call_addr, isolate_instructions, vm_instructions);
frame_index++;
continue;
} else if (function.IsNull()) {
@@ -24601,8 +24607,7 @@
// non-symbolic stack traces.
PrintSymbolicStackFrameIndex(&buffer, frame_index);
PrintNonSymbolicStackFrameBody(
- &buffer, call_addr, isolate_instructions, vm_instructions,
- isolate_relocated_address);
+ &buffer, call_addr, isolate_instructions, vm_instructions);
frame_index++;
continue;
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 22e2810..5084dff 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5959,6 +5959,26 @@
friend class Object;
};
+// An ImageHeader contains extra information about serialized AOT snapshots.
+//
+// To avoid changing the embedder to return more information about an AOT
+// snapshot and possibly disturbing existing clients of that interface, we
+// serialize a single ImageHeader object at the start of any text segments.
+class ImageHeader : public Object {
+ public:
+ static intptr_t InstanceSize() {
+ return RoundedAllocationSize(sizeof(ImageHeaderLayout));
+ }
+ // There are no public methods for the ImageHeader contents, because
+ // all access to the contents is handled by methods on the Image class.
+
+ private:
+ // Note there are no New() methods for ImageHeaders. Unstead, the serializer
+ // writes the ImageHeaderLayout object manually at the start of the text
+ // segment in precompiled snapshots.
+ FINAL_HEAP_OBJECT_IMPLEMENTATION(ImageHeader, Object);
+};
+
// A WeakSerializationReference (WSR) denotes a type of weak reference to a
// target object. In particular, objects that can only be reached from roots via
// WSR edges during serialization of AOT snapshots should not be serialized. Of
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 319cff6..80eb1e8 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -2,13 +2,13 @@
// 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.
+#include "vm/canonical_tables.h"
#include "vm/compiler/assembler/disassembler.h"
#include "vm/debugger.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
-#include "vm/type_table.h"
namespace dart {
@@ -684,6 +684,10 @@
Object::PrintJSONImpl(stream, ref);
}
+void ImageHeader::PrintJSONImpl(JSONStream* stream, bool ref) const {
+ Object::PrintJSONImpl(stream, ref);
+}
+
void WeakSerializationReference::PrintJSONImpl(JSONStream* stream,
bool ref) const {
JSONObject jsobj(stream);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 3dfd910..de63846 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -223,6 +223,10 @@
instance_size = element->HeapSize();
break;
}
+ case kImageHeaderCid: {
+ instance_size = ImageHeader::InstanceSize();
+ break;
+ }
case kWeakSerializationReferenceCid: {
instance_size = WeakSerializationReference::InstanceSize();
break;
@@ -564,6 +568,7 @@
NULL_VISITOR(Capability)
NULL_VISITOR(SendPort)
NULL_VISITOR(TransferableTypedData)
+NULL_VISITOR(ImageHeader)
REGULAR_VISITOR(Pointer)
NULL_VISITOR(DynamicLibrary)
VARIABLE_NULL_VISITOR(Instructions, Instructions::Size(raw_obj))
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 39e0254..82b9df0 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1404,6 +1404,25 @@
}
};
+class ImageHeaderLayout : public ObjectLayout {
+ RAW_HEAP_OBJECT_IMPLEMENTATION(ImageHeader);
+
+ VISIT_NOTHING();
+ // The offset of the corresponding BSS section from this text section.
+ uword bss_offset_;
+ // The relocated address of this text section in the shared object. Properly
+ // filled for ELF snapshots, always 0 in assembly snapshots. (For the latter,
+ // we instead get the value during BSS initialization and store it there.)
+ uword instructions_relocated_address_;
+ // The offset of the GNU build ID section description field from this text
+ // section.
+ uword build_id_offset_;
+ // The length of the GNU build ID section description field.
+ uword build_id_length_;
+
+ friend class Image;
+};
+
class WeakSerializationReferenceLayout : public ObjectLayout {
RAW_HEAP_OBJECT_IMPLEMENTATION(WeakSerializationReference);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 68a56b3..36deccf 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -582,6 +582,7 @@
MESSAGE_SNAPSHOT_UNREACHABLE(UnwindError);
MESSAGE_SNAPSHOT_UNREACHABLE(FutureOr);
MESSAGE_SNAPSHOT_UNREACHABLE(WeakSerializationReference);
+MESSAGE_SNAPSHOT_UNREACHABLE(ImageHeader);
MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index e20e9a9..2c7a938 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -13,6 +13,7 @@
#include "platform/unicode.h"
#include "vm/base64.h"
+#include "vm/canonical_tables.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/cpu.h"
#include "vm/dart_api_impl.h"
@@ -45,7 +46,6 @@
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/timeline.h"
-#include "vm/type_table.h"
#include "vm/version.h"
namespace dart {
diff --git a/runtime/vm/service/service_extension.md b/runtime/vm/service/service_extension.md
index 7bdca7f..b564c2a 100644
--- a/runtime/vm/service/service_extension.md
+++ b/runtime/vm/service/service_extension.md
@@ -108,6 +108,7 @@
### getHttpEnableTimelineLogging
```
+@Deprecated
HttpTimelineLoggingState getHttpEnableTimelineLogging(string isolateId)
```
@@ -120,6 +121,7 @@
### setHttpEnableTimelineLogging
```
+@Deprecated
Success setHttpEnableTimelineLogging(string isolateId, bool enable)
```
@@ -130,6 +132,22 @@
See [Success](#success).
+### httpEnableTimelineLogging
+
+```
+HttpTimelineLoggingState httpEnableTimelineLogging(string isolateId, bool enable [optional])
+```
+
+The _httpEnableTimelineLogging_ RPC is used to set and inspect the value of
+`HttpClient.enableTimelineLogging`, which determines if HTTP client requests
+should be logged to the timeline. If `enable` is provided, the state of
+`HttpClient.enableTimelineLogging` will be updated to the value of `enable`.
+
+If the value of `HttpClient.enableTimelineLogging` is changed, a
+`HttpTimelineLoggingStateChange` event will be sent on the `Extension` stream.
+
+See [HttpTimelineLoggingState](#httptimelineloggingstate).
+
## Public Types
### File
@@ -325,3 +343,4 @@
1.0 | Initial revision.
1.1 | Added `lastReadTime` and `lastWriteTime` properties to `SocketStatistic`.
1.2 | Added `getOpenFiles`, `getOpenFileById`, `getSpawnedProcesses`, and `getSpawnedProcessById` RPCs and added `OpenFile` and `SpawnedProcess` objects.
+1.3 | Added `httpEnableTimelineLogging` RPC and `HttpTimelineLoggingStateChange` event, deprecated `getHttpEnableTimelineLogging` and `setHttpEnableTimelineLogging`.
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 607f35d..c8a05fa 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -907,12 +907,10 @@
SnapshotWriter::SnapshotWriter(Thread* thread,
Snapshot::Kind kind,
- ReAlloc alloc,
- DeAlloc dealloc,
intptr_t initial_size,
ForwardList* forward_list,
bool can_send_any_object)
- : BaseWriter(alloc, dealloc, initial_size),
+ : BaseWriter(initial_size),
thread_(thread),
kind_(kind),
object_store_(isolate()->object_store()),
@@ -1576,22 +1574,9 @@
}
}
-static uint8_t* malloc_allocator(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
- return reinterpret_cast<uint8_t*>(new_ptr);
-}
-
-static void malloc_deallocator(uint8_t* ptr) {
- free(reinterpret_cast<void*>(ptr));
-}
-
MessageWriter::MessageWriter(bool can_send_any_object)
: SnapshotWriter(Thread::Current(),
Snapshot::kMessage,
- malloc_allocator,
- malloc_deallocator,
kInitialSize,
&forward_list_,
can_send_any_object),
@@ -1629,9 +1614,10 @@
}
MessageFinalizableData* finalizable_data = finalizable_data_;
- finalizable_data_ = NULL;
- return Message::New(dest_port, buffer(), BytesWritten(), finalizable_data,
- priority);
+ finalizable_data_ = nullptr;
+ intptr_t size;
+ uint8_t* buffer = Steal(&size);
+ return Message::New(dest_port, buffer, size, finalizable_data, priority);
}
} // namespace dart
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 6df1270..d685fb2 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -429,14 +429,14 @@
class BaseWriter : public StackResource {
public:
- uint8_t* buffer() { return stream_.buffer(); }
+ uint8_t* Steal(intptr_t* length) { return stream_.Steal(length); }
intptr_t BytesWritten() const { return stream_.bytes_written(); }
// Writes raw data to the stream (basic type).
// sizeof(T) must be in {1,2,4,8}.
template <typename T>
void Write(T value) {
- WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
+ MallocWriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
}
void WriteClassIDValue(classid_t value) { Write<uint32_t>(value); }
@@ -491,13 +491,8 @@
}
protected:
- BaseWriter(ReAlloc alloc, DeAlloc dealloc, intptr_t initial_size)
- : StackResource(Thread::Current()),
- buffer_(NULL),
- stream_(&buffer_, alloc, initial_size),
- dealloc_(dealloc) {
- ASSERT(alloc != NULL);
- }
+ explicit BaseWriter(intptr_t initial_size)
+ : StackResource(Thread::Current()), stream_(initial_size) {}
~BaseWriter() {}
void ReserveHeader() {
@@ -506,21 +501,20 @@
}
void FillHeader(Snapshot::Kind kind) {
- Snapshot* header = reinterpret_cast<Snapshot*>(stream_.buffer());
+ intptr_t length;
+ Snapshot* header = reinterpret_cast<Snapshot*>(Steal(&length));
header->set_magic();
- header->set_length(stream_.bytes_written());
+ header->set_length(length);
header->set_kind(kind);
}
void FreeBuffer() {
- dealloc_(stream_.buffer());
- stream_.set_buffer(NULL);
+ intptr_t unused;
+ free(Steal(&unused));
}
private:
- uint8_t* buffer_;
- WriteStream stream_;
- DeAlloc dealloc_;
+ MallocWriteStream stream_;
DISALLOW_IMPLICIT_CONSTRUCTORS(BaseWriter);
};
@@ -586,8 +580,6 @@
protected:
SnapshotWriter(Thread* thread,
Snapshot::Kind kind,
- ReAlloc alloc,
- DeAlloc dealloc,
intptr_t initial_size,
ForwardList* forward_list,
bool can_send_any_object);
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index ed50a53..4ff7ccf 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -52,12 +52,6 @@
return false;
}
-static uint8_t* malloc_allocator(uint8_t* ptr,
- intptr_t old_size,
- intptr_t new_size) {
- return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
-}
-
// Compare two Dart_CObject object graphs rooted in first and
// second. The second graph will be destroyed by this operation no matter
// whether the graphs are equal or not.
@@ -755,10 +749,14 @@
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
- FullSnapshotWriter writer(Snapshot::kFull, NULL,
- &isolate_snapshot_data_buffer, &malloc_allocator,
- NULL, /*image_writer*/ nullptr);
+ MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
+ FullSnapshotWriter writer(
+ Snapshot::kFull, /*vm_snapshot_data=*/nullptr, &isolate_snapshot_data,
+ /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
writer.WriteFullSnapshot();
+ // Take ownership so it doesn't get freed by the stream destructor.
+ intptr_t unused;
+ isolate_snapshot_data_buffer = isolate_snapshot_data.Steal(&unused);
}
// Now Create another isolate using the snapshot and execute a method
@@ -2019,8 +2017,6 @@
// For performance, we'd like single-byte headers when ids are omitted.
// If this starts failing, consider renumbering the snapshot ids.
EXPECT_EQ(1, writer.BytesWritten());
-
- free(writer.buffer());
}
TEST_CASE(IsKernelNegative) {
@@ -2075,12 +2071,11 @@
// Verify that snapshot writing succeeds if erasure is not required.
if (!required) {
// Write snapshot with object content.
- uint8_t* isolate_snapshot_data_buffer;
+ MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
FullSnapshotWriter writer(
- Snapshot::kFull, NULL, &isolate_snapshot_data_buffer,
- &malloc_allocator, NULL, /*image_writer*/ nullptr);
+ Snapshot::kFull, /*vm_snapshot_data=*/nullptr, &isolate_snapshot_data,
+ /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
writer.WriteFullSnapshot();
- free(isolate_snapshot_data_buffer);
}
}
}
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index 4fb75a0..fac122b 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -5,6 +5,7 @@
#include "vm/symbols.h"
#include "platform/unicode.h"
+#include "vm/canonical_tables.h"
#include "vm/handles.h"
#include "vm/hash_table.h"
#include "vm/heap/safepoint.h"
@@ -14,7 +15,6 @@
#include "vm/raw_object.h"
#include "vm/reusable_handles.h"
#include "vm/snapshot_ids.h"
-#include "vm/type_table.h"
#include "vm/visitor.h"
namespace dart {
@@ -44,59 +44,6 @@
return String::FromUTF16(data, len, space);
}
-template <typename CharType>
-class CharArray {
- public:
- CharArray(const CharType* data, intptr_t len) : data_(data), len_(len) {
- hash_ = String::Hash(data, len);
- }
- StringPtr ToSymbol() const {
- String& result = String::Handle(StringFrom(data_, len_, Heap::kOld));
- result.SetCanonical();
- result.SetHash(hash_);
- return result.raw();
- }
- bool Equals(const String& other) const {
- ASSERT(other.HasHash());
- if (other.Hash() != hash_) {
- return false;
- }
- return other.Equals(data_, len_);
- }
- intptr_t Hash() const { return hash_; }
-
- private:
- const CharType* data_;
- intptr_t len_;
- intptr_t hash_;
-};
-typedef CharArray<uint8_t> Latin1Array;
-typedef CharArray<uint16_t> UTF16Array;
-
-class StringSlice {
- public:
- StringSlice(const String& str, intptr_t begin_index, intptr_t length)
- : str_(str), begin_index_(begin_index), len_(length) {
- hash_ = is_all() ? str.Hash() : String::Hash(str, begin_index, length);
- }
- StringPtr ToSymbol() const;
- bool Equals(const String& other) const {
- ASSERT(other.HasHash());
- if (other.Hash() != hash_) {
- return false;
- }
- return other.Equals(str_, begin_index_, len_);
- }
- intptr_t Hash() const { return hash_; }
-
- private:
- bool is_all() const { return begin_index_ == 0 && len_ == str_.Length(); }
- const String& str_;
- intptr_t begin_index_;
- intptr_t len_;
- intptr_t hash_;
-};
-
StringPtr StringSlice::ToSymbol() const {
if (is_all() && str_.IsOld()) {
str_.SetCanonical();
@@ -110,26 +57,6 @@
}
}
-class ConcatString {
- public:
- ConcatString(const String& str1, const String& str2)
- : str1_(str1), str2_(str2), hash_(String::HashConcat(str1, str2)) {}
- StringPtr ToSymbol() const;
- bool Equals(const String& other) const {
- ASSERT(other.HasHash());
- if (other.Hash() != hash_) {
- return false;
- }
- return other.EqualsConcat(str1_, str2_);
- }
- intptr_t Hash() const { return hash_; }
-
- private:
- const String& str1_;
- const String& str2_;
- intptr_t hash_;
-};
-
StringPtr ConcatString::ToSymbol() const {
String& result = String::Handle(String::Concat(str1_, str2_, Heap::kOld));
result.SetCanonical();
@@ -137,53 +64,6 @@
return result.raw();
}
-class SymbolTraits {
- public:
- static const char* Name() { return "SymbolTraits"; }
- static bool ReportStats() { return false; }
-
- static bool IsMatch(const Object& a, const Object& b) {
- const String& a_str = String::Cast(a);
- const String& b_str = String::Cast(b);
- ASSERT(a_str.HasHash());
- ASSERT(b_str.HasHash());
- if (a_str.Hash() != b_str.Hash()) {
- return false;
- }
- intptr_t a_len = a_str.Length();
- if (a_len != b_str.Length()) {
- return false;
- }
- // Use a comparison which does not consider the state of the canonical bit.
- return a_str.Equals(b_str, 0, a_len);
- }
- template <typename CharType>
- static bool IsMatch(const CharArray<CharType>& array, const Object& obj) {
- return array.Equals(String::Cast(obj));
- }
- static bool IsMatch(const StringSlice& slice, const Object& obj) {
- return slice.Equals(String::Cast(obj));
- }
- static bool IsMatch(const ConcatString& concat, const Object& obj) {
- return concat.Equals(String::Cast(obj));
- }
- static uword Hash(const Object& key) { return String::Cast(key).Hash(); }
- template <typename CharType>
- static uword Hash(const CharArray<CharType>& array) {
- return array.Hash();
- }
- static uword Hash(const StringSlice& slice) { return slice.Hash(); }
- static uword Hash(const ConcatString& concat) { return concat.Hash(); }
- template <typename CharType>
- static ObjectPtr NewKey(const CharArray<CharType>& array) {
- return array.ToSymbol();
- }
- static ObjectPtr NewKey(const StringSlice& slice) { return slice.ToSymbol(); }
- static ObjectPtr NewKey(const ConcatString& concat) {
- return concat.ToSymbol();
- }
-};
-typedef UnorderedHashSet<SymbolTraits> SymbolTable;
const char* Symbols::Name(SymbolId symbol) {
ASSERT((symbol > kIllegal) && (symbol < kNullCharId));
@@ -211,7 +91,7 @@
// Create all predefined symbols.
ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kNullCharId);
- SymbolTable table(zone, vm_isolate->object_store()->symbol_table());
+ CanonicalStringSet table(zone, vm_isolate->object_store()->symbol_table());
// First set up all the predefined string symbols.
// Create symbols for language keywords. Some keywords are equal to
@@ -251,7 +131,7 @@
ASSERT(vm_isolate == Dart::vm_isolate());
Zone* zone = Thread::Current()->zone();
- SymbolTable table(zone, vm_isolate->object_store()->symbol_table());
+ CanonicalStringSet table(zone, vm_isolate->object_store()->symbol_table());
// Lookup all the predefined string symbols and language keyword symbols
// and cache them in the read only handles for fast access.
@@ -292,140 +172,14 @@
const intptr_t initial_size = (isolate == Dart::vm_isolate())
? kInitialVMIsolateSymtabSize
: kInitialSymtabSize;
- Array& array =
- Array::Handle(HashTables::New<SymbolTable>(initial_size, Heap::kOld));
+ Array& array = Array::Handle(
+ HashTables::New<CanonicalStringSet>(initial_size, Heap::kOld));
isolate->object_store()->set_symbol_table(array);
}
-void Symbols::Compact() {
- Thread* thread = Thread::Current();
- ASSERT(thread->isolate() != Dart::vm_isolate());
- HANDLESCOPE(thread);
- Zone* zone = thread->zone();
- ObjectStore* object_store = thread->isolate()->object_store();
-
- // 1. Drop the tables and do a full garbage collection.
- object_store->set_symbol_table(Object::empty_array());
- object_store->set_canonical_types(Object::empty_array());
- object_store->set_canonical_type_parameters(Object::empty_array());
- object_store->set_canonical_type_arguments(Object::empty_array());
- thread->heap()->CollectAllGarbage();
-
- // 2. Walk the heap to find surviving canonical objects.
- GrowableArray<String*> symbols;
- GrowableArray<class Type*> types;
- GrowableArray<class TypeParameter*> type_params;
- GrowableArray<class TypeArguments*> type_args;
- class SymbolCollector : public ObjectVisitor {
- public:
- SymbolCollector(Thread* thread,
- GrowableArray<String*>* symbols,
- GrowableArray<class Type*>* types,
- GrowableArray<class TypeParameter*>* type_params,
- GrowableArray<class TypeArguments*>* type_args)
- : symbols_(symbols),
- types_(types),
- type_params_(type_params),
- type_args_(type_args),
- zone_(thread->zone()) {}
-
- void VisitObject(ObjectPtr obj) {
- if (obj->ptr()->IsCanonical()) {
- if (obj->IsStringInstance()) {
- symbols_->Add(&String::Handle(zone_, String::RawCast(obj)));
- } else if (obj->IsType()) {
- types_->Add(&Type::Handle(zone_, Type::RawCast(obj)));
- } else if (obj->IsTypeParameter()) {
- type_params_->Add(
- &TypeParameter::Handle(zone_, TypeParameter::RawCast(obj)));
- } else if (obj->IsTypeArguments()) {
- type_args_->Add(
- &TypeArguments::Handle(zone_, TypeArguments::RawCast(obj)));
- }
- }
- }
-
- private:
- GrowableArray<String*>* symbols_;
- GrowableArray<class Type*>* types_;
- GrowableArray<class TypeParameter*>* type_params_;
- GrowableArray<class TypeArguments*>* type_args_;
- Zone* zone_;
- };
-
- {
- HeapIterationScope iteration(thread);
- SymbolCollector visitor(thread, &symbols, &types, &type_params, &type_args);
- iteration.IterateObjects(&visitor);
- }
-
- // 3. Build new tables from the surviving canonical objects.
- {
- Array& array = Array::Handle(
- zone,
- HashTables::New<SymbolTable>(symbols.length() * 4 / 3, Heap::kOld));
- SymbolTable table(zone, array.raw());
- for (intptr_t i = 0; i < symbols.length(); i++) {
- String& symbol = *symbols[i];
- ASSERT(symbol.IsString());
- ASSERT(symbol.IsCanonical());
- bool present = table.Insert(symbol);
- ASSERT(!present);
- }
- object_store->set_symbol_table(table.Release());
- }
-
- {
- Array& array = Array::Handle(zone, HashTables::New<CanonicalTypeSet>(
- types.length() * 4 / 3, Heap::kOld));
- CanonicalTypeSet table(zone, array.raw());
- for (intptr_t i = 0; i < types.length(); i++) {
- class Type& type = *types[i];
- ASSERT(type.IsType());
- ASSERT(type.IsCanonical());
- bool present = table.Insert(type);
- // Two recursive types with different topology (and hashes) may be equal.
- ASSERT(!present || type.IsRecursive());
- }
- object_store->set_canonical_types(table.Release());
- }
-
- {
- Array& array =
- Array::Handle(zone, HashTables::New<CanonicalTypeParameterSet>(
- type_params.length() * 4 / 3, Heap::kOld));
- CanonicalTypeParameterSet table(zone, array.raw());
- for (intptr_t i = 0; i < type_params.length(); i++) {
- class TypeParameter& type_param = *type_params[i];
- ASSERT(type_param.IsTypeParameter());
- ASSERT(type_param.IsCanonical());
- if (type_param.IsDeclaration()) continue;
- bool present = table.Insert(type_param);
- ASSERT(!present);
- }
- object_store->set_canonical_type_parameters(table.Release());
- }
-
- {
- Array& array =
- Array::Handle(zone, HashTables::New<CanonicalTypeArgumentsSet>(
- type_args.length() * 4 / 3, Heap::kOld));
- CanonicalTypeArgumentsSet table(zone, array.raw());
- for (intptr_t i = 0; i < type_args.length(); i++) {
- class TypeArguments& type_arg = *type_args[i];
- ASSERT(type_arg.IsTypeArguments());
- ASSERT(type_arg.IsCanonical());
- bool present = table.Insert(type_arg);
- // Two recursive types with different topology (and hashes) may be equal.
- ASSERT(!present || type_arg.IsRecursive());
- }
- object_store->set_canonical_type_arguments(table.Release());
- }
-}
-
void Symbols::GetStats(Isolate* isolate, intptr_t* size, intptr_t* capacity) {
ASSERT(isolate != NULL);
- SymbolTable table(isolate->object_store()->symbol_table());
+ CanonicalStringSet table(isolate->object_store()->symbol_table());
*size = table.NumOccupied();
*capacity = table.NumEntries();
table.Release();
@@ -588,7 +342,7 @@
{
Isolate* vm_isolate = Dart::vm_isolate();
data = vm_isolate->object_store()->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.GetOrNull(str);
table.Release();
}
@@ -617,7 +371,7 @@
// Uncommon case: We are at a safepoint, all mutators are stopped and we
// have therefore exclusive access to the symbol table.
data = object_store->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.InsertNewOrGet(str);
object_store->set_symbol_table(table.Release());
} else {
@@ -626,7 +380,7 @@
{
SafepointReadRwLocker sl(thread, group->symbols_lock());
data = object_store->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.GetOrNull(str);
table.Release();
}
@@ -635,7 +389,7 @@
if (symbol.IsNull()) {
auto insert_or_get = [&]() {
data = object_store->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.InsertNewOrGet(str);
object_store->set_symbol_table(table.Release());
};
@@ -672,7 +426,7 @@
{
Isolate* vm_isolate = Dart::vm_isolate();
data = vm_isolate->object_store()->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.GetOrNull(str);
table.Release();
}
@@ -693,13 +447,13 @@
RELEASE_ASSERT(FLAG_enable_isolate_groups || !USING_PRODUCT);
#endif
data = object_store->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.GetOrNull(str);
table.Release();
} else {
SafepointReadRwLocker sl(thread, group->symbols_lock());
data = object_store->symbol_table();
- SymbolTable table(&key, &value, &data);
+ CanonicalStringSet table(&key, &value, &data);
symbol ^= table.GetOrNull(str);
table.Release();
}
@@ -795,7 +549,7 @@
void Symbols::DumpTable(Isolate* isolate) {
OS::PrintErr("symbols:\n");
- SymbolTable table(isolate->object_store()->symbol_table());
+ CanonicalStringSet table(isolate->object_store()->symbol_table());
table.Dump();
table.Release();
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index df2a0f0..84b028b 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -654,9 +654,6 @@
// Initialize and setup a symbol table for the isolate.
static void SetupSymbolTable(Isolate* isolate);
- // Treat the symbol table as weak and collect garbage.
- static void Compact();
-
// Creates a Symbol given a C string that is assumed to contain
// UTF-8 encoded characters and '\0' is considered a termination character.
// TODO(7123) - Rename this to FromCString(....).
diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h
index b81e29d..e1f6c15 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -127,12 +127,12 @@
constexpr bool operator!=(const ObjectPtr& other) const {
return tagged_pointer_ != other.tagged_pointer_;
}
- bool operator==(const nullptr_t& other) { return tagged_pointer_ == 0; }
- bool operator!=(const nullptr_t& other) { return tagged_pointer_ != 0; }
- constexpr bool operator==(const nullptr_t& other) const {
+ bool operator==(const std::nullptr_t& other) { return tagged_pointer_ == 0; }
+ bool operator!=(const std::nullptr_t& other) { return tagged_pointer_ != 0; }
+ constexpr bool operator==(const std::nullptr_t& other) const {
return tagged_pointer_ == 0;
}
- constexpr bool operator!=(const nullptr_t& other) const {
+ constexpr bool operator!=(const std::nullptr_t& other) const {
return tagged_pointer_ != 0;
}
@@ -183,7 +183,7 @@
ObjectPtr() : tagged_pointer_(0) {}
explicit constexpr ObjectPtr(uword tagged) : tagged_pointer_(tagged) {}
explicit constexpr ObjectPtr(intptr_t tagged) : tagged_pointer_(tagged) {}
- constexpr ObjectPtr(nullptr_t) : tagged_pointer_(0) {} // NOLINT
+ constexpr ObjectPtr(std::nullptr_t) : tagged_pointer_(0) {} // NOLINT
explicit ObjectPtr(ObjectLayout* heap_object)
: tagged_pointer_(reinterpret_cast<uword>(heap_object) + kHeapObjectTag) {
}
@@ -225,7 +225,7 @@
klass##Ptr() : base##Ptr() {} \
explicit constexpr klass##Ptr(uword tagged) : base##Ptr(tagged) {} \
explicit constexpr klass##Ptr(intptr_t tagged) : base##Ptr(tagged) {} \
- constexpr klass##Ptr(nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \
+ constexpr klass##Ptr(std::nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \
explicit klass##Ptr(const ObjectLayout* untagged) \
: base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {} \
};
@@ -242,6 +242,7 @@
DEFINE_TAGGED_POINTER(Library, Object)
DEFINE_TAGGED_POINTER(Namespace, Object)
DEFINE_TAGGED_POINTER(KernelProgramInfo, Object)
+DEFINE_TAGGED_POINTER(ImageHeader, Object)
DEFINE_TAGGED_POINTER(WeakSerializationReference, Object)
DEFINE_TAGGED_POINTER(Code, Object)
DEFINE_TAGGED_POINTER(Bytecode, Object)
diff --git a/runtime/vm/type_table.h b/runtime/vm/type_table.h
deleted file mode 100644
index 99fad9f..0000000
--- a/runtime/vm/type_table.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2016, 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.
-
-#ifndef RUNTIME_VM_TYPE_TABLE_H_
-#define RUNTIME_VM_TYPE_TABLE_H_
-
-#include "platform/assert.h"
-#include "vm/hash_table.h"
-#include "vm/object.h"
-
-namespace dart {
-
-class CanonicalTypeKey {
- public:
- explicit CanonicalTypeKey(const Type& key) : key_(key) {}
- bool Matches(const Type& arg) const { return key_.Equals(arg); }
- uword Hash() const { return key_.Hash(); }
- const Type& key_;
-
- private:
- DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical Type based on its hash.
-class CanonicalTypeTraits {
- public:
- static const char* Name() { return "CanonicalTypeTraits"; }
- static bool ReportStats() { return false; }
-
- // Called when growing the table.
- static bool IsMatch(const Object& a, const Object& b) {
- ASSERT(a.IsType() && b.IsType());
- const Type& arg1 = Type::Cast(a);
- const Type& arg2 = Type::Cast(b);
- return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
- }
- static bool IsMatch(const CanonicalTypeKey& a, const Object& b) {
- ASSERT(b.IsType());
- return a.Matches(Type::Cast(b));
- }
- static uword Hash(const Object& key) {
- ASSERT(key.IsType());
- return Type::Cast(key).Hash();
- }
- static uword Hash(const CanonicalTypeKey& key) { return key.Hash(); }
- static ObjectPtr NewKey(const CanonicalTypeKey& obj) {
- return obj.key_.raw();
- }
-};
-typedef UnorderedHashSet<CanonicalTypeTraits> CanonicalTypeSet;
-
-class CanonicalTypeParameterKey {
- public:
- explicit CanonicalTypeParameterKey(const TypeParameter& key) : key_(key) {}
- bool Matches(const TypeParameter& arg) const { return key_.Equals(arg); }
- uword Hash() const { return key_.Hash(); }
- const TypeParameter& key_;
-
- private:
- DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical TypeParameter based on its hash.
-class CanonicalTypeParameterTraits {
- public:
- static const char* Name() { return "CanonicalTypeParameterTraits"; }
- static bool ReportStats() { return false; }
-
- // Called when growing the table.
- static bool IsMatch(const Object& a, const Object& b) {
- ASSERT(a.IsTypeParameter() && b.IsTypeParameter());
- const TypeParameter& arg1 = TypeParameter::Cast(a);
- const TypeParameter& arg2 = TypeParameter::Cast(b);
- return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
- }
- static bool IsMatch(const CanonicalTypeParameterKey& a, const Object& b) {
- ASSERT(b.IsTypeParameter());
- return a.Matches(TypeParameter::Cast(b));
- }
- static uword Hash(const Object& key) {
- ASSERT(key.IsTypeParameter());
- return TypeParameter::Cast(key).Hash();
- }
- static uword Hash(const CanonicalTypeParameterKey& key) { return key.Hash(); }
- static ObjectPtr NewKey(const CanonicalTypeParameterKey& obj) {
- return obj.key_.raw();
- }
-};
-typedef UnorderedHashSet<CanonicalTypeParameterTraits>
- CanonicalTypeParameterSet;
-
-class CanonicalTypeArgumentsKey {
- public:
- explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {}
- bool Matches(const TypeArguments& arg) const {
- return key_.Equals(arg) && (key_.Hash() == arg.Hash());
- }
- uword Hash() const { return key_.Hash(); }
- const TypeArguments& key_;
-
- private:
- DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical TypeArguments based on its hash.
-class CanonicalTypeArgumentsTraits {
- public:
- static const char* Name() { return "CanonicalTypeArgumentsTraits"; }
- static bool ReportStats() { return false; }
-
- // Called when growing the table.
- static bool IsMatch(const Object& a, const Object& b) {
- ASSERT(a.IsTypeArguments() && b.IsTypeArguments());
- const TypeArguments& arg1 = TypeArguments::Cast(a);
- const TypeArguments& arg2 = TypeArguments::Cast(b);
- return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
- }
- static bool IsMatch(const CanonicalTypeArgumentsKey& a, const Object& b) {
- ASSERT(b.IsTypeArguments());
- return a.Matches(TypeArguments::Cast(b));
- }
- static uword Hash(const Object& key) {
- ASSERT(key.IsTypeArguments());
- return TypeArguments::Cast(key).Hash();
- }
- static uword Hash(const CanonicalTypeArgumentsKey& key) { return key.Hash(); }
- static ObjectPtr NewKey(const CanonicalTypeArgumentsKey& obj) {
- return obj.key_.raw();
- }
-};
-typedef UnorderedHashSet<CanonicalTypeArgumentsTraits>
- CanonicalTypeArgumentsSet;
-
-} // namespace dart
-
-#endif // RUNTIME_VM_TYPE_TABLE_H_
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index a919b39..2cd70b1 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -21,6 +21,7 @@
"bootstrap_natives.h",
"bss_relocs.cc",
"bss_relocs.h",
+ "canonical_tables.h",
"class_finalizer.cc",
"class_finalizer.h",
"class_id.h",
@@ -341,7 +342,6 @@
"token.h",
"token_position.cc",
"token_position.h",
- "type_table.h",
"type_testing_stubs.cc",
"type_testing_stubs.h",
"unibrow-inl.h",
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index 151dae4..b7ca682 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -18,6 +18,7 @@
import 'dart:developer' hide log;
import 'dart:_internal'
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
+import 'dart:isolate' show Isolate;
import 'dart:math';
import 'dart:io';
import 'dart:typed_data';
@@ -1473,8 +1474,14 @@
///
/// Default is `false`.
static set enableTimelineLogging(bool value) {
- _enableTimelineLogging =
- valueOfNonNullableParamWithDefault<bool>(value, false);
+ final enabled = valueOfNonNullableParamWithDefault<bool>(value, false);
+ if (enabled != _enableTimelineLogging) {
+ postEvent('HttpTimelineLoggingStateChange', {
+ 'isolateId': Service.getIsolateID(Isolate.current),
+ 'enabled': enabled,
+ });
+ }
+ _enableTimelineLogging = enabled;
}
/// Current state of HTTP request logging from all [HttpClient]s to the
diff --git a/sdk/lib/_internal/allowed_experiments.json b/sdk/lib/_internal/allowed_experiments.json
index 235e683..464837e 100644
--- a/sdk/lib/_internal/allowed_experiments.json
+++ b/sdk/lib/_internal/allowed_experiments.json
@@ -76,6 +76,9 @@
"meta": {
"experimentSet": "nullSafety"
},
+ "native_stack_traces": {
+ "experimentSet": "nullSafety"
+ },
"path": {
"experimentSet": "nullSafety"
},
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
index 66c6bb1..f4ab556 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
@@ -56,3 +56,9 @@
@patch
Object? extractTypeArguments<T>(T instance, Function extract) =>
dart.extractTypeArguments<T>(instance, extract);
+
+@patch
+T createSentinel<T>() => throw UnsupportedError('createSentinel');
+
+@patch
+bool isSentinel(dynamic value) => throw UnsupportedError('isSentinel');
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 88ca3d2..3c9aed9 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -277,3 +277,11 @@
// This body is unused, only here for type analysis.
return JS('String', '# + #', a, b);
}
+
+/// Creates a JavaScript value that can be used as a sentinel for uninitialized
+/// late fields and variables.
+external T createJsSentinel<T>();
+
+/// Returns `true` if [value] is the sentinel JavaScript value created through
+/// [createJsSentinel].
+external bool isJsSentinel(dynamic value);
diff --git a/sdk/lib/_internal/js_runtime/lib/internal_patch.dart b/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
index 2dc838d..9bf6da6 100644
--- a/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
@@ -7,7 +7,8 @@
import 'dart:_js_primitives' show printString;
import 'dart:_js_helper' show patch;
import 'dart:_interceptors' show JSArray;
-import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+import 'dart:_foreign_helper'
+ show JS, JS_GET_FLAG, createJsSentinel, isJsSentinel;
@patch
@pragma('dart2js:tryInline')
@@ -64,3 +65,11 @@
// the returned value flows to the result of extractTypeArguments.
return extract();
}
+
+@patch
+@pragma('dart2js:tryInline')
+T createSentinel<T>() => createJsSentinel<T>();
+
+@patch
+@pragma('dart2js:tryInline')
+bool isSentinel(dynamic value) => isJsSentinel(value);
diff --git a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
index 6e19c50..6a7b7b3 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -1297,7 +1297,7 @@
/// Extract the sign bit from each lane return them in the first 4 bits.
int get signMask {
var view = _uint32view;
- var mx, my, mz, mw;
+ int mx, my, mz, mw;
_list[0] = x;
_list[1] = y;
_list[2] = z;
diff --git a/sdk/lib/_internal/js_runtime/pubspec.yaml b/sdk/lib/_internal/js_runtime/pubspec.yaml
index 96abf65..f42b2cd 100644
--- a/sdk/lib/_internal/js_runtime/pubspec.yaml
+++ b/sdk/lib/_internal/js_runtime/pubspec.yaml
@@ -2,5 +2,3 @@
# make it easier to develop on dart2js.
name: js_runtime
publish_to: none
-environment:
- sdk: '>=2.10.0-0.0 <3.0.0'
diff --git a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
index 8f46e53..79b69ee 100644
--- a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
+++ b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
@@ -2,5 +2,3 @@
# make it easer to depend on libraries.dart from sdk packages like dart2js.
name: sdk_library_metadata
publish_to: none
-environment:
- sdk: '>=2.10.0-0.0 <3.0.0'
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index fa16bc6..812f18f 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -188,3 +188,9 @@
// This function can be used by tests to enforce garbage collection.
static void collectAllGarbage() native "Internal_collectAllGarbage";
}
+
+@patch
+T createSentinel<T>() => throw UnsupportedError('createSentinel');
+
+@patch
+bool isSentinel(dynamic value) => throw UnsupportedError('isSentinel');
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 8da9d66..5c42772 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -13739,7 +13739,7 @@
contextElement = _parseDocument!.createElement(tagName);
_parseDocument!.body!.append(contextElement);
}
- var fragment;
+ DocumentFragment fragment;
if (Range.supportsCreateContextualFragment &&
_canBeUsedToCreateContextualFragment) {
_parseRange!.selectNodeContents(contextElement);
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 21640b2..1b501e9 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -473,7 +473,7 @@
'version and onUpgradeNeeded must be specified together'));
}
try {
- var request;
+ OpenDBRequest request;
if (version != null) {
request = _open(name, version);
} else {
diff --git a/sdk/lib/internal/internal_sources.gni b/sdk/lib/internal/internal_sources.gni
index c35e678..25b98b9 100644
--- a/sdk/lib/internal/internal_sources.gni
+++ b/sdk/lib/internal/internal_sources.gni
@@ -14,6 +14,7 @@
"iterable.dart",
"linked_list.dart",
"list.dart",
+ "lowering.dart",
"print.dart",
"sort.dart",
"symbol.dart",
diff --git a/sdk/lib/internal/lowering.dart b/sdk/lib/internal/lowering.dart
new file mode 100644
index 0000000..30a0cea
--- /dev/null
+++ b/sdk/lib/internal/lowering.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, 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.
+
+part of dart._internal;
+
+external T createSentinel<T>();
+
+external bool isSentinel(dynamic value);
diff --git a/sdk/lib/io/network_profiling.dart b/sdk/lib/io/network_profiling.dart
index 7121d3c..cb3d1ba 100644
--- a/sdk/lib/io/network_profiling.dart
+++ b/sdk/lib/io/network_profiling.dart
@@ -6,7 +6,7 @@
// TODO(bkonyi): refactor into io_resource_info.dart
const int _versionMajor = 1;
-const int _versionMinor = 2;
+const int _versionMinor = 3;
const String _tcpSocket = 'tcp';
const String _udpSocket = 'udp';
@@ -14,10 +14,14 @@
@pragma('vm:entry-point', !const bool.fromEnvironment("dart.vm.product"))
abstract class _NetworkProfiling {
// Http relative RPCs
+ @Deprecated('Use httpEnableTimelineLogging instead')
static const _kGetHttpEnableTimelineLogging =
'ext.dart.io.getHttpEnableTimelineLogging';
+ @Deprecated('Use httpEnableTimelineLogging instead')
static const _kSetHttpEnableTimelineLogging =
'ext.dart.io.setHttpEnableTimelineLogging';
+ static const _kHttpEnableTimelineLogging =
+ 'ext.dart.io.httpEnableTimelineLogging';
// Socket relative RPCs
static const _kClearSocketProfileRPC = 'ext.dart.io.clearSocketProfile';
static const _kGetSocketProfileRPC = 'ext.dart.io.getSocketProfile';
@@ -33,6 +37,7 @@
static void _registerServiceExtension() {
registerExtension(_kGetHttpEnableTimelineLogging, _serviceExtensionHandler);
registerExtension(_kSetHttpEnableTimelineLogging, _serviceExtensionHandler);
+ registerExtension(_kHttpEnableTimelineLogging, _serviceExtensionHandler);
registerExtension(_kGetSocketProfileRPC, _serviceExtensionHandler);
registerExtension(_kStartSocketProfilingRPC, _serviceExtensionHandler);
registerExtension(_kPauseSocketProfilingRPC, _serviceExtensionHandler);
@@ -51,6 +56,12 @@
case _kSetHttpEnableTimelineLogging:
responseJson = _setHttpEnableTimelineLogging(parameters);
break;
+ case _kHttpEnableTimelineLogging:
+ if (parameters.containsKey('enable')) {
+ _setHttpEnableTimelineLogging(parameters);
+ }
+ responseJson = _getHttpEnableTimelineLogging();
+ break;
case _kGetSocketProfileRPC:
responseJson = _SocketProfile.toJson();
break;
@@ -108,7 +119,7 @@
if (enable != 'true' && enable != 'false') {
throw _invalidArgument(kEnable, enable);
}
- HttpClient.enableTimelineLogging = (enable == 'true');
+ HttpClient.enableTimelineLogging = enable == 'true';
return _success();
}
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 358ce45..1ca6f0b 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -41,7 +41,6 @@
LanguageFeatures/Simple-bounds/dynamic/type-aliases/*: Skip # Not migrated to NNBD
LanguageFeatures/Simple-bounds/static/*: Skip # Not migrated to NNBD
LanguageFeatures/Simple-bounds/static/type-aliases/*: Skip # Not migrated to NNBD
-LanguageFeatures/Spread-collections/*: Skip # Not migrated to NNBD
LanguageFeatures/Triple-Shift/*: Skip # Triple shift is not implemented yet
LanguageFeatures/regression/34560_t02/01: Skip # Type aliases are not fully implemented
LibTest/io/RawDatagramSocket/*: Skip # https://github.com/dart-lang/co19/issues/195
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
new file mode 100644
index 0000000..e307833
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2020, 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 'null_assertions_test_lib.dart';
+
+void main() {
+ var flagEnabled = false;
+ testNativeNullAssertions(flagEnabled);
+ testJSInvocationNullAssertions(flagEnabled);
+}
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
new file mode 100644
index 0000000..0eb3965
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, 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.
+
+// dart2jsOptions=--native-null-assertions
+
+import 'null_assertions_test_lib.dart';
+
+void main() {
+ var flagEnabled = true;
+ testNativeNullAssertions(flagEnabled);
+ testJSInvocationNullAssertions(flagEnabled);
+}
diff --git a/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart b/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart
new file mode 100644
index 0000000..9dd2be1
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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 '../native_testing.dart';
+import 'null_assertions_lib.dart';
+
+// Implementation of `JSInterface` except in a folder that is not part of the
+// allowlist for the `--native-null-assertions` flag. This file is not treated
+// as a web library, and therefore the `JS()` invocations should not be checked.
+
+@Native('CCCInNonWebLibrary')
+class CCCInNonWebLibrary implements JSInterface {
+ String get name => JS('String', '#.name', this);
+ String? get optName => JS('String|Null', '#.optName', this);
+}
diff --git a/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart b/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart
new file mode 100644
index 0000000..0554ab4
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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 '../native_testing.dart';
+import 'null_assertions_lib.dart';
+
+// Implementation of `JSInterface` in a folder that is explicitly part of the
+// allowlist for the `--native-null-assertions` flag. This file is treated as a
+// web library, and therefore the `JS()` invocations should be checked.
+
+@Native('CCCInWebLibrary')
+class CCCInWebLibrary implements JSInterface {
+ String get name => JS('String', '#.name', this);
+ String? get optName => JS('String|Null', '#.optName', this);
+}
diff --git a/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart b/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart
new file mode 100644
index 0000000..894fdf0
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2020, 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 '../native_testing.dart';
+
+abstract class NativeInterface {
+ int get size;
+ String get name;
+ String? get optName;
+ int method1();
+ String method2();
+ String? optMethod();
+}
+
+@Native("AAA")
+class AAA implements NativeInterface {
+ int get size native;
+ String get name native;
+ String? get optName native;
+ int method1() native;
+ String method2() native;
+ String? optMethod() native;
+}
+
+abstract class JSInterface {
+ String get name;
+ String? get optName;
+}
+
+class BBB implements NativeInterface {
+ int get size => 300;
+ String get name => 'Brenda';
+ String? get optName => name;
+ int method1() => 400;
+ String method2() => 'brilliant!';
+ String? optMethod() => method2();
+}
diff --git a/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart b/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
new file mode 100644
index 0000000..3f1f540
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
@@ -0,0 +1,193 @@
+// Copyright (c) 2020, 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 '../native_testing.dart';
+import 'js_invocations_in_non_web_library.dart';
+import 'js_invocations_in_web_library.dart';
+import 'null_assertions_lib.dart';
+
+/// Returns an 'AAA' object that satisfies the interface.
+AAA makeA() native;
+
+/// Returns an 'AAA' object where each method breaks the interface's contract.
+AAA makeAX() native;
+
+/// Returns a 'JSInterface' object whose `JS()` invocations exist in a library
+/// that is part of the allowlist.
+CCCInWebLibrary makeWebC() native;
+
+/// Returns the same as above but where each method breaks the interface's
+/// contract.
+CCCInWebLibrary makeWebCX() native;
+
+/// Returns a 'JSInterface' object whose `JS()` invocations exist in a library
+/// that is not part of the allowlist.
+CCCInNonWebLibrary makeNonWebC() native;
+
+/// Returns the same as above but where each method breaks the interface's
+/// contract.
+CCCInNonWebLibrary makeNonWebCX() native;
+
+void setup() {
+ JS('', r"""
+(function(){
+ function AAA(s,n,m1,m2) {
+ this.size = s;
+ this.name = n;
+ this.optName = n;
+ this._m1 = m1;
+ this._m2 = m2;
+ }
+ AAA.prototype.method1 = function(){return this._m1};
+ AAA.prototype.method2 = function(){return this._m2};
+ AAA.prototype.optMethod = function(){return this._m2};
+
+ makeA = function() {
+ return new AAA(100, 'Albert', 200, 'amazing!');
+ };
+ makeAX = function() {
+ return new AAA(void 0, void 0, void 0, void 0);
+ };
+
+ self.nativeConstructor(AAA);
+
+ function CCCInWebLibrary(n) {
+ this.name = n;
+ this.optName = n;
+ }
+ function CCCInNonWebLibrary(n) {
+ this.name = n;
+ this.optName = n;
+ }
+
+ makeWebC = function() {
+ return new CCCInWebLibrary('Carol');
+ };
+ makeWebCX = function() {
+ return new CCCInWebLibrary(void 0);
+ };
+ makeNonWebC = function() {
+ return new CCCInNonWebLibrary('Carol');
+ };
+ makeNonWebCX = function() {
+ return new CCCInNonWebLibrary(void 0);
+ };
+
+ self.nativeConstructor(CCCInWebLibrary);
+ self.nativeConstructor(CCCInNonWebLibrary);
+})()""");
+}
+
+// The 'NativeInterface' version of the code is passed both native and Dart
+// objects, so there will be an interceptor dispatch to the method. This tests
+// that the null-check exists in the forwarding method.
+//
+// The 'AAA' version of the code is passed only objects of a single native
+// class, so the native method can be inlined (which happens in the optimizer).
+// This tests that the null-check exists in the 'inlined' code.
+
+@pragma('dart2js:noInline')
+String describeNativeInterface(NativeInterface o) {
+ return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
+}
+
+@pragma('dart2js:noInline')
+String describeAAA(AAA o) {
+ return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptNativeInterface(NativeInterface o) {
+ return '${o.optName} ${o.optMethod()}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptAAA(AAA o) {
+ return '${o.optName} ${o.optMethod()}';
+}
+
+@pragma('dart2js:noInline')
+String describeJSInterface(JSInterface o) {
+ return '${o.name}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptJSInterface(JSInterface o) {
+ return '${o.optName}';
+}
+
+const expectedA = 'Albert amazing! 100 200';
+const expectedB = 'Brenda brilliant! 300 400';
+const expectedOptA = 'Albert amazing!';
+const expectedOptB = 'Brenda brilliant!';
+const expectedOptX = 'null null';
+
+const expectedC = 'Carol';
+const expectedOptC = 'Carol';
+const expectedOptCX = 'null';
+
+// Test that `--native-null-assertions` injects null-checks on the returned
+// value of native methods with a non-nullable return type in an opt-in library.
+void testNativeNullAssertions(bool flagEnabled) {
+ nativeTesting();
+ setup();
+ AAA a = makeA();
+ BBB b = BBB();
+
+ Expect.equals(expectedA, describeNativeInterface(a));
+ Expect.equals(expectedB, describeNativeInterface(b));
+
+ Expect.equals(expectedA, describeAAA(a));
+
+ AAA x = makeAX(); // This object returns `null`!
+ var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
+ checkExpectation(() => describeNativeInterface(x));
+ checkExpectation(() => describeAAA(x));
+
+ checkExpectation(() => x.name);
+ checkExpectation(() => x.size);
+ checkExpectation(() => x.method1());
+ checkExpectation(() => x.method2());
+
+ // Now test that a nullable return type does not have a check.
+ Expect.equals(expectedOptA, describeOptNativeInterface(a));
+ Expect.equals(expectedOptB, describeOptNativeInterface(b));
+ Expect.equals(expectedOptX, describeOptNativeInterface(x));
+
+ Expect.equals(expectedOptA, describeOptAAA(a));
+ Expect.equals(expectedOptX, describeOptAAA(x));
+}
+
+// Test that `--native-null-assertions` injects null-checks on the returned
+// value of `JS()` invocations with a non-nullable static type in an opt-in
+// library.
+void testJSInvocationNullAssertions(bool flagEnabled) {
+ nativeTesting();
+ setup();
+
+ CCCInWebLibrary webC = makeWebC();
+ CCCInWebLibrary webCX = makeWebCX();
+
+ CCCInNonWebLibrary nonWebC = makeNonWebC();
+ CCCInNonWebLibrary nonWebCX = makeNonWebCX();
+
+ Expect.equals(expectedC, describeJSInterface(webC));
+ Expect.equals(expectedC, describeJSInterface(nonWebC));
+
+ // If invocations are in a web library, this should throw if null checks are
+ // enabled.
+ var checkExpectationWeb = flagEnabled ? Expect.throws : (f) => f();
+ checkExpectationWeb(() => describeJSInterface(webCX));
+
+ // If invocations are not in a web library, there should not be a null check
+ // regardless if the flag is enabled or not.
+ var checkExpectationNonWeb = (f) => f();
+ checkExpectationNonWeb(() => describeJSInterface(nonWebCX));
+
+ // Test that invocations with a nullable static type do not have checks.
+ Expect.equals(expectedOptC, describeOptJSInterface(webC));
+ Expect.equals(expectedOptC, describeOptJSInterface(nonWebC));
+ Expect.equals(expectedOptCX, describeOptJSInterface(webCX));
+ Expect.equals(expectedOptCX, describeOptJSInterface(nonWebCX));
+}
diff --git a/tests/dart2js/native/null_assertions_opt_in_lib.dart b/tests/dart2js/native/null_assertions_opt_in_lib.dart
deleted file mode 100644
index e08c788..0000000
--- a/tests/dart2js/native/null_assertions_opt_in_lib.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2020, 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 'native_testing.dart';
-
-abstract class Interface {
- int get size;
- String get name;
- String? get optName;
- int method1();
- String method2();
-}
-
-@Native("AAA")
-class AAA implements Interface {
- int get size native;
- String get name native;
- String? get optName native;
- int method1() native;
- String method2() native;
-}
-
-/// Returns an 'AAA' object that satisfies the interface.
-AAA makeA() native;
-
-/// Returns an 'AAA' object where each method breaks the interface's contract.
-AAA makeAX() native;
-
-void setup() {
- JS('', r"""
-(function(){
- function AAA(s,n,m1,m2) {
- this.size = s;
- this.name = n;
- this.optName = n;
- this._m1 = m1;
- this._m2 = m2;
- }
- AAA.prototype.method1 = function(){return this._m1};
- AAA.prototype.method2 = function(){return this._m2};
-
- makeA = function() {return new AAA(100, 'Albert', 200, 'amazing!')};
- makeAX = function() {return new AAA(void 0, void 0, void 0, void 0)};
-
- self.nativeConstructor(AAA);
-})()""");
-}
-
-class BBB implements Interface {
- int get size => 300;
- String get name => 'Brenda';
- String? get optName => name;
- int method1() => 400;
- String method2() => 'brilliant!';
-}
-
-List<Interface> items = [makeA(), BBB()];
diff --git a/tests/dart2js/native/null_assertions_test.dart b/tests/dart2js/native/null_assertions_test.dart
deleted file mode 100644
index 0a07785..0000000
--- a/tests/dart2js/native/null_assertions_test.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2020, 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.
-
-// Requirements=nnbd-weak
-// dart2jsOptions=--null-assertions
-
-// @dart=2.8
-
-// Test that `--null-assertions` injects null-checks on the returned value of
-// native methods with a non-nullable return type in an opt-in library.
-
-import 'native_testing.dart';
-import 'null_assertions_opt_in_lib.dart' as lib;
-
-// The 'Interface' version of the code is passed both native and Dart objects,
-// so there will be an interceptor dispatch to the method. This tests that the
-// null-check exists in the forwarding method.
-//
-// The 'AAA' version of the code is passed only objects of a single native
-// class, so the native method can be inlined (which happens in the optimizer).
-// This tests that the null-check exists in the 'inlined' code.
-
-@pragma('dart2js:noInline')
-String describeInterface(lib.Interface o) {
- return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
-}
-
-@pragma('dart2js:noInline')
-String describeAAA(lib.AAA o) {
- return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
-}
-
-@pragma('dart2js:noInline')
-void checkOptNameInterface(lib.Interface o, dynamic expected) {
- Expect.equals(expected, o.optName);
-}
-
-@pragma('dart2js:noInline')
-void checkOptNameAAA(lib.AAA o, dynamic expected) {
- Expect.equals(expected, o.optName);
-}
-
-const expectedA = 'Albert amazing! 100 200';
-const expectedB = 'Brenda brilliant! 300 400';
-
-void main() {
- nativeTesting();
- lib.setup();
- lib.AAA a = lib.makeA();
- lib.BBB b = lib.BBB();
-
- Expect.equals(expectedA, describeInterface(a));
- Expect.equals(expectedB, describeInterface(b));
-
- Expect.equals(expectedA, describeAAA(a));
-
- lib.AAA x = lib.makeAX(); // This object returns `null`!
- Expect.throws(() => describeInterface(x));
- Expect.throws(() => describeAAA(x));
-
- Expect.throws(() => x.name);
- Expect.throws(() => x.size);
- Expect.throws(() => x.method1());
- Expect.throws(() => x.method2());
-
- // Now test that a nullable return type does not have a check.
- checkOptNameInterface(a, 'Albert');
- checkOptNameInterface(b, 'Brenda');
- checkOptNameInterface(x, null);
-
- checkOptNameAAA(a, 'Albert');
- checkOptNameAAA(x, null);
-}
diff --git a/tests/language/nnbd/inference/variable_initialization_promotion_test.dart b/tests/language/nnbd/inference/variable_initialization_promotion_test.dart
new file mode 100644
index 0000000..634caaa
--- /dev/null
+++ b/tests/language/nnbd/inference/variable_initialization_promotion_test.dart
@@ -0,0 +1,338 @@
+// Copyright (c) 2020, 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 '../../static_type_helper.dart';
+
+/// Test that the type of a local variable is treated as a "type of interest"
+/// for the variable, and that for non-final variables, the initialization (if
+/// any) is treated as an assignment for the purposes of promotion.
+
+/// Verify that the declared type of a local variable is a type of interest.
+void declaredTypeIsATypeOfInterest() {
+ // Check that a variable declared with a non-nullable type can be assignment
+ // demoted back to its declared type after being promoted.
+ {
+ num x = 3;
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ }
+
+ // Check that a variable declared with a nullable type can be assignment
+ // promoted to the non-nullable variant of its type, and demoted back to both
+ // the non-nullable variant and the declared type after being promoted.
+ {
+ num? x = (3 as num?);
+ x.expectStaticType<Exactly<num?>>();
+ // This should promote to num, since num and num? should both be types of
+ // interest.
+ x = 3;
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ // Verify that demotion back to num? works
+ x = null;
+ x.expectStaticType<Exactly<num?>>();
+ }
+
+ // Check that a late variable declared with a non-nullable type can be
+ // assignment demoted back to its declared type after being promoted.
+ {
+ late num x = 3;
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ }
+
+ // Check that a late variable declared with a nullable type can be assignment
+ // promoted to the non-nullable variant of its type, and demoted back to both
+ // the non-nullable variant and the declared type after being promoted.
+ {
+ late num? x = (3 as num?);
+ x.expectStaticType<Exactly<num?>>();
+ // This should promote to num, since num and num? should both be types of
+ // interest.
+ x = 3;
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ // Verify that demotion back to num? works
+ x = null;
+ x.expectStaticType<Exactly<num?>>();
+ }
+
+ // Final variables are not re-assignable, but can still be subject to
+ // to assignment based promotion and demotion in a few situations.
+
+ // Check that a late final variable declared with a non-nullable type can be
+ // assignment demoted back to its declared type after being promoted.
+ {
+ late final num x;
+ // Make x potentially assigned, and initialize it
+ if (num == num) {
+ x = 3.5;
+ }
+ // Branch will not be taken to avoid a double initialization error
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ x = 3.5; // Demote to num.
+ x.expectStaticType<Exactly<num>>();
+ }
+ }
+
+ // Check that a final variable declared with a non-nullable type can be
+ // assignment promoted to the non-nullable variant of its type.
+ {
+ final num? x;
+ // Promote to num, since num is a type of interest
+ x = 3;
+ // Verify that we have promoted to num
+ x.expectStaticType<Exactly<num>>();
+ }
+
+ // Check that a late final variable declared with a non-nullable type can be
+ // assignment promoted to the non-nullable variant of its type.
+ {
+ late final num? x;
+ // Promote to num, since num is a type of interest
+ x = 3;
+ // Verify that we have promoted to num
+ x.expectStaticType<Exactly<num>>();
+ }
+}
+
+/// Verify that the inferred type of a local variable is a type of interest.
+void inferredTypeIsATypeOfInterest() {
+ // Check that a variable inferred with a non-nullable type can be
+ // assignment demoted back to its declared type after being promoted.
+ {
+ var x = (3 as num);
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ }
+
+ // Check that a variable inferred to have a nullable type can be assignment
+ // promoted to the non-nullable variant of its type, and demoted back to both
+ // the non-nullable variant and the declared type after being promoted.
+ {
+ var x = (3 as num?);
+ x.expectStaticType<Exactly<num?>>();
+ // This should promote to num, since num and num? should both be types of
+ // interest.
+ x = 3;
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ // Verify that demotion back to num? works
+ x = null;
+ x.expectStaticType<Exactly<num?>>();
+ }
+
+ // Check that a variable inferred with a non-nullable type can be
+ // assignment demoted back to its declared type after being promoted.
+ {
+ late var x = (3 as num);
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ }
+
+ // Check that a late variable inferred to have a nullable type can be
+ // assignment promoted to the non-nullable variant of its type, and demoted
+ // back to both the non-nullable variant and the declared type after being
+ // promoted.
+ {
+ late var x = (3 as num?);
+ x.expectStaticType<Exactly<num?>>();
+ // This should promote to num, since num and num? should both be types of
+ // interest.
+ x = 3;
+ x.expectStaticType<Exactly<num>>();
+ // Promote x to int
+ if (x is int) {
+ x.expectStaticType<Exactly<int>>();
+ // Verify that demotion back to num works
+ x = 3.5;
+ x.expectStaticType<Exactly<num>>();
+ }
+ x.expectStaticType<Exactly<num>>();
+ // Verify that demotion back to num? works
+ x = null;
+ x.expectStaticType<Exactly<num?>>();
+ }
+}
+
+/// Verify that the initializer on a mutable variable is treated as if it were
+/// an assignment for the purposes of promotion, and therefore assigning a
+/// non-nullable value can promote to a non-nullable variant of the declared
+/// type.
+void initializersOnVarPromote() {
+ // Check that a variable declared to have a nullable type can be promoted on
+ // initialization to the non-nullable variant of its type, demoted back to the
+ // declared type, and assignment promoted to the non-nullable variant of the
+ // declared type.
+ {
+ num? x = 3;
+ // Verify that we have promoted to num
+ x.expectStaticType<Exactly<num>>();
+ // Verify that num? is a type of interest by demoting to it
+ x = null;
+ x.expectStaticType<Exactly<num?>>();
+ // Verify that num is a type of interest by promoting to it.
+ x = 3;
+ x.expectStaticType<Exactly<num>>();
+ }
+
+ // Check that a late variable declared to have a nullable type can be promoted
+ // on initialization to the non-nullable variant of its type, demoted back to
+ // the declared type, and assignment promoted to the non-nullable variant of
+ // the declared type.
+ {
+ late num? x = 3;
+ // Verify that we have promoted to num
+ x.expectStaticType<Exactly<num>>();
+ // Verify that num? is a type of interest by demoting to it
+ x = null;
+ x.expectStaticType<Exactly<num?>>();
+ // Verify that num is a type of interest by promoting to it.
+ x = 3;
+ x.expectStaticType<Exactly<num>>();
+ }
+}
+
+/// Verify that the initializer on a final variable is not treated as if it were
+/// an assignment for the purposes of promotion, and therefore assigning a
+/// non-nullable value does not promote to a non-nullable variant of the
+/// declared type.
+void initializersOnFinalDoNotPromote() {
+ // Check that a final nullable variable initialized with a non-nullable value
+ // does not get promoted by the initializer to the non-nullable variant of the
+ // type.
+ {
+ final num? x = 3;
+ // Verify that we have not promoted to num
+ x.expectStaticType<Exactly<num?>>();
+ }
+
+ // Check that a late final nullable variable initialized with a non-nullable
+ // value does not get promoted by the initializer to the non-nullable variant
+ // of the type.
+ {
+ late final num? x = 3;
+ // Verify that we have not promoted to num
+ x.expectStaticType<Exactly<num?>>();
+ }
+}
+
+/// Check that when an initializer is a promoted type variable `X & T`, the
+/// inferred type of the variable is `X`, but that the variable is immediately
+/// promoted to `X & T`.
+void typeVariableTypedVariableInferencePromotes<T>(T x0, T x1) {
+ if (x0 is num) {
+ // Promote `x0` to T & num
+
+ {
+ // Declare y, which should have inferred type T, and be promoted to T &
+ // num
+ var y = x0;
+ // Check that y is assignable to z, and hence that y is still promoted to
+ // T & num
+ num z = y;
+ // Check that y can be demoted to T.
+ y = x1;
+ // T & num is still a type of interest, and hence this assignment should
+ // promote to T & num.
+ y = x0;
+ // Check that y is assignable to z, and hence that y has been promoted T &
+ // num
+ z = y;
+ }
+
+ {
+ // Declare y, which should have inferred type T, and be promoted to T &
+ // num
+ late var y = x0;
+ // Check that y is assignable to z, and hence that y is still promoted to
+ // T & num
+ num z = y;
+ // Check that y can be demoted to T.
+ y = x1;
+ // T & num is still a type of interest, and hence this assignment should
+ // promote to T & num.
+ y = x0;
+ // Check that y is assignable to z, and hence that y has been promoted T &
+ // num
+ z = y;
+ }
+
+ {
+ // Declare y, which should have inferred type T, and be promoted to T &
+ // num
+ final y = x0;
+ // Check that y is assignable to z, and hence that y is still promoted to
+ // T & num
+ num z = y;
+ }
+
+ {
+ // Declare y, which should have inferred type T, and be promoted to T &
+ // num
+ late final y = x0;
+ // Check that y is assignable to z, and hence that y is still promoted to
+ // T & num
+ num z = y;
+ }
+ }
+}
+
+void main() {
+ declaredTypeIsATypeOfInterest();
+ inferredTypeIsATypeOfInterest();
+ initializersOnVarPromote();
+ initializersOnFinalDoNotPromote();
+ typeVariableTypedVariableInferencePromotes<num>(3, 3.5);
+}
diff --git a/tests/language/nnbd/inference/variables_initialized_to_null_test.dart b/tests/language/nnbd/inference/variables_initialized_to_null_test.dart
new file mode 100644
index 0000000..77ffaa9
--- /dev/null
+++ b/tests/language/nnbd/inference/variables_initialized_to_null_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2020, 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';
+
+/// Test that variables which are initialized to Null are inferred at type
+/// `dynamic`.
+
+var global0 = null;
+var global1 = null as Null;
+
+class Test {
+ static var static0 = null;
+ static var static1 = null as Null;
+
+ var instance0 = null;
+ var instance1 = null as Null;
+}
+
+/// For each category of variable and each style of initialization, we test that
+/// the variable verify that the type is not `Never` by verifying that a value
+/// of type `Object` may be assigned to it, and then check that the type is
+/// `dynamic` (or `Never` which has been eliminated) by verifying that an
+/// arbitrary method may be called on it.
+
+void test() {
+ final Object three = 3;
+ {
+ global0 = three;
+ Expect.isFalse(global0.isEven);
+ global1 = three;
+ Expect.isFalse(global1.isEven);
+ }
+ {
+ Test.static0 = three;
+ Expect.isFalse(Test.static0.isEven);
+ Test.static1 = three;
+ Expect.isFalse(Test.static1.isEven);
+ }
+ {
+ var o = new Test();
+ o.instance0 = three;
+ Expect.isFalse(o.instance0.isEven);
+ o.instance1 = three;
+ Expect.isFalse(o.instance1.isEven);
+ }
+ {
+ var local0 = null;
+ var local1 = null as Null;
+
+ local0 = three;
+ Expect.isFalse(local0.isEven);
+ local1 = three;
+ Expect.isFalse(local1.isEven);
+ }
+}
+
+void main() {
+ test();
+}
diff --git a/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart b/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart
index 6f5c2c0..4f39726 100644
--- a/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart
+++ b/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart
@@ -10,9 +10,9 @@
import 'dart:core';
main() async {
- late a = 0; //# 01: ok
- late b = await 0; //# 02: compile-time error
- late c = () async => await 42; //# 03: ok
- late d = () async { await 42; }; //# 04: ok
- var e = () async { late e2 = await 42; }; //# 05: compile-time error
+ late final a = 0; //# 01: ok
+ late var b = await 0; //# 02: compile-time error
+ late Function c = () async => await 42; //# 03: ok
+ late var d = () async { await 42; }; //# 04: ok
+ var e = () async { late final e2 = await 42; }; //# 05: compile-time error
}
diff --git a/tests/language/operator/number_operator_context_test.dart b/tests/language/operator/number_operator_context_test.dart
index 898f139..3c587d8 100644
--- a/tests/language/operator/number_operator_context_test.dart
+++ b/tests/language/operator/number_operator_context_test.dart
@@ -4,7 +4,7 @@
// Test the new context type rules for number operators,
// as modified by Null Safety
-import "static_type_helper.dart";
+import "../static_type_helper.dart";
// The context rules for `e` of the form:
// For e1 + e2, e1 - e2, e1 * e2, e1 % e2 or e1.remainder(e2),,
diff --git a/tests/language/operator/number_operator_error_test.dart b/tests/language/operator/number_operator_error_test.dart
index 90e4cf0..f402e51 100644
--- a/tests/language/operator/number_operator_error_test.dart
+++ b/tests/language/operator/number_operator_error_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// Test the new context type rules for number operators,
-import "static_type_helper.dart";
+import "../static_type_helper.dart";
// as modified by Null Safety
void main() {
diff --git a/tests/language/operator/number_operator_typing_test.dart b/tests/language/operator/number_operator_typing_test.dart
index 62e452a..c650e61 100644
--- a/tests/language/operator/number_operator_typing_test.dart
+++ b/tests/language/operator/number_operator_typing_test.dart
@@ -4,7 +4,7 @@
// Test the rules for static types of number operators,
// as modified by Null Safety
-import "static_type_helper.dart";
+import "../static_type_helper.dart";
// ignore_for_file: receiver_of_type_never
diff --git a/tests/language/spread_collections/type_error_test.dart b/tests/language/spread_collections/type_error_test.dart
index ccfc61a..3fe731a 100644
--- a/tests/language/spread_collections/type_error_test.dart
+++ b/tests/language/spread_collections/type_error_test.dart
@@ -20,7 +20,7 @@
var _ = <int>{...<String>[]}; //# 09: compile-time error
// Downcast element.
- var _ = <int>[...<num>[1, 2]]); //# 10: compile-time error
- var _ = <int, int>{...<num, num>{1: 1, 2: 2}}); //# 11: compile-time error
- var _ = <int>{...<num>[1, 2]}); //# 12: compile-time error
+ var _ = <int>[...<num>[1, 2]]; //# 10: compile-time error
+ var _ = <int, int>{...<num, num>{1: 1, 2: 2}}; //# 11: compile-time error
+ var _ = <int>{...<num>[1, 2]}; //# 12: compile-time error
}
diff --git a/tests/language/operator/static_type_helper.dart b/tests/language/static_type_helper.dart
similarity index 91%
rename from tests/language/operator/static_type_helper.dart
rename to tests/language/static_type_helper.dart
index 50cdace..9484387 100644
--- a/tests/language/operator/static_type_helper.dart
+++ b/tests/language/static_type_helper.dart
@@ -64,7 +64,7 @@
/// Checks that an expression is assignable to [T1], [T2] and [Object].
///
-/// This ensures that the type of the expression is a non-`dynamic`
-/// type assignable to both [T1] and [T2], and if those are unrelated,
-/// it must be an intersection type.
+/// This ensures that the static type of the expression is either dynamic,
+/// Never, or a type assignable to both [T1] and [T2], and if those are
+/// unrelated, it must be an intersection type.
void checkIntersectionType<T1, T2>(T1 v1, T2 v2, Object v3) {}
diff --git a/tests/standalone/check_for_aot_snapshot_jit_test.dart b/tests/standalone/check_for_aot_snapshot_jit_test.dart
index 851dc0c5..a1dd29d 100644
--- a/tests/standalone/check_for_aot_snapshot_jit_test.dart
+++ b/tests/standalone/check_for_aot_snapshot_jit_test.dart
@@ -20,7 +20,7 @@
final kernelOutput = d.uri.resolve('pow_test.dill').path;
final aotOutput = d.uri.resolve('pow_test.aot').path;
- final genKernelResult = Process.runSync(
+ final genKernelResult = runAndPrintOutput(
'pkg/vm/tool/gen_kernel',
[
'--aot',
@@ -31,8 +31,9 @@
],
);
Expect.equals(genKernelResult.exitCode, 0);
+ print("Ran successfully.\n");
- final genAotResult = Process.runSync(
+ final genAotResult = runAndPrintOutput(
genSnapshot,
[
'--snapshot_kind=app-aot-elf',
@@ -41,8 +42,9 @@
],
);
Expect.equals(genAotResult.exitCode, 0);
+ print("Ran successfully.\n");
- final runAotResult = Process.runSync(
+ final runAotResult = runAndPrintOutput(
exePath,
[
'run',
@@ -56,4 +58,19 @@
"pow_test.aot is an AOT snapshot and should be run with 'dartaotruntime'",
],
);
+ print('Got expected error result.');
+}
+
+ProcessResult runAndPrintOutput(String command, List<String> args) {
+ print('Running $command ${args.join(' ')}...');
+ final result = Process.runSync(command, args);
+ if (result.stdout.isNotEmpty) {
+ print("stdout: ");
+ print(result.stdout);
+ }
+ if (result.stderr.isNotEmpty) {
+ print("stderr: ");
+ print(result.stderr);
+ }
+ return result;
}
diff --git a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
index 5750ab5..f6b3360 100644
--- a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
+++ b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
@@ -40,7 +40,7 @@
return; // Generated dwarf.so not available on the test device.
}
- final dwarf = Dwarf.fromFile("dwarf_obfuscate.so");
+ final dwarf = Dwarf.fromFile("dwarf_obfuscate.so")!;
await base.checkStackTrace(rawStack, dwarf, expectedCallsInfo);
}
diff --git a/tests/standalone/dwarf_stack_trace_test.dart b/tests/standalone/dwarf_stack_trace_test.dart
index 9cf2cb0..236a21e 100644
--- a/tests/standalone/dwarf_stack_trace_test.dart
+++ b/tests/standalone/dwarf_stack_trace_test.dart
@@ -40,7 +40,7 @@
return; // Generated dwarf.so not available on the test device.
}
- final dwarf = Dwarf.fromFile("dwarf.so");
+ final dwarf = Dwarf.fromFile("dwarf.so")!;
await checkStackTrace(rawStack, dwarf, expectedCallsInfo);
}
@@ -86,7 +86,7 @@
Expect.isNotNull(externalCallInfo);
final allCallInfo = dwarf.callInfoFor(addr, includeInternalFrames: true);
Expect.isNotNull(allCallInfo);
- for (final call in allCallInfo) {
+ for (final call in allCallInfo!) {
Expect.isTrue(call is DartCallInfo, "got non-Dart call info ${call}");
}
Expect.deepEquals(externalCallInfo, allCallInfo);
diff --git a/tests/standalone/io/socket_connect_consume_write_close_test.dart b/tests/standalone/io/socket_connect_consume_write_close_test.dart
index 8b021abd..f593c79 100644
--- a/tests/standalone/io/socket_connect_consume_write_close_test.dart
+++ b/tests/standalone/io/socket_connect_consume_write_close_test.dart
@@ -18,7 +18,12 @@
// without listening on the stream.
asyncStart();
ServerSocket.bind(InternetAddress.loopbackIPv4, 0).then((server) {
- server.listen((_) {});
+ late Socket ref;
+ server.listen((socket) {
+ // Create a reference to the connected socket so it's not prematurely
+ // collected.
+ ref = socket;
+ });
Socket.connect("127.0.0.1", server.port).then((socket) {
socket.add([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
socket.close();
diff --git a/tests/standalone_2/check_for_aot_snapshot_jit_test.dart b/tests/standalone_2/check_for_aot_snapshot_jit_test.dart
index 851dc0c5..a1dd29d 100644
--- a/tests/standalone_2/check_for_aot_snapshot_jit_test.dart
+++ b/tests/standalone_2/check_for_aot_snapshot_jit_test.dart
@@ -20,7 +20,7 @@
final kernelOutput = d.uri.resolve('pow_test.dill').path;
final aotOutput = d.uri.resolve('pow_test.aot').path;
- final genKernelResult = Process.runSync(
+ final genKernelResult = runAndPrintOutput(
'pkg/vm/tool/gen_kernel',
[
'--aot',
@@ -31,8 +31,9 @@
],
);
Expect.equals(genKernelResult.exitCode, 0);
+ print("Ran successfully.\n");
- final genAotResult = Process.runSync(
+ final genAotResult = runAndPrintOutput(
genSnapshot,
[
'--snapshot_kind=app-aot-elf',
@@ -41,8 +42,9 @@
],
);
Expect.equals(genAotResult.exitCode, 0);
+ print("Ran successfully.\n");
- final runAotResult = Process.runSync(
+ final runAotResult = runAndPrintOutput(
exePath,
[
'run',
@@ -56,4 +58,19 @@
"pow_test.aot is an AOT snapshot and should be run with 'dartaotruntime'",
],
);
+ print('Got expected error result.');
+}
+
+ProcessResult runAndPrintOutput(String command, List<String> args) {
+ print('Running $command ${args.join(' ')}...');
+ final result = Process.runSync(command, args);
+ if (result.stdout.isNotEmpty) {
+ print("stdout: ");
+ print(result.stdout);
+ }
+ if (result.stderr.isNotEmpty) {
+ print("stderr: ");
+ print(result.stderr);
+ }
+ return result;
}
diff --git a/tests/standalone_2/io/socket_connect_consume_write_close_test.dart b/tests/standalone_2/io/socket_connect_consume_write_close_test.dart
index 8b021abd..3dc0ab5 100644
--- a/tests/standalone_2/io/socket_connect_consume_write_close_test.dart
+++ b/tests/standalone_2/io/socket_connect_consume_write_close_test.dart
@@ -18,7 +18,12 @@
// without listening on the stream.
asyncStart();
ServerSocket.bind(InternetAddress.loopbackIPv4, 0).then((server) {
- server.listen((_) {});
+ Socket ref;
+ server.listen((socket) {
+ // Create a reference to the connected socket so it's not prematurely
+ // collected.
+ ref = socket;
+ });
Socket.connect("127.0.0.1", server.port).then((socket) {
socket.add([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
socket.close();
diff --git a/tools/VERSION b/tools/VERSION
index 6b0416f..e3ee7ca 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
#
CHANNEL dev
MAJOR 2
-MINOR 10
+MINOR 11
PATCH 0
-PRERELEASE 156
+PRERELEASE 157
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index cb9855d..88ab3c4 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -822,39 +822,6 @@
"builder-tag": "vm_nnbd"
}
},
- "dartk-(linux|mac|win)-(debug|product|release)-(ia32|simarm|simarm64|x64)-ast": {
- "options": {
- "builder-tag": "ast",
- "gen-kernel-options": [
- "--no-gen-bytecode"
- ]
- }
- },
- "dartkp-(linux|mac)-(debug|product|release)-x64-ast": {
- "options": {
- "builder-tag": "ast",
- "gen-kernel-options": [
- "--no-gen-bytecode"
- ]
- }
- },
- "dartkp-(linux|mac)-(debug|product|release)-simarm64-ast": {
- "options": {
- "builder-tag": "ast",
- "use-elf": true,
- "gen-kernel-options": [
- "--no-gen-bytecode"
- ]
- }
- },
- "dartkp-linux-(debug|product|release)-simarm-crossword-ast": {
- "options": {
- "builder-tag": "crossword_ast",
- "gen-kernel-options": [
- "--no-gen-bytecode"
- ]
- }
- },
"dartk-checked-(linux|mac|win)-(debug|product|release)-(ia32|x64)": {
"options": {
"enable-asserts": true
@@ -891,134 +858,6 @@
}
},
"app_jitk-(linux|mac|win)-(debug|product|release)-(ia32|x64)": {},
- "dartkb-interpret-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_interpreter",
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations"
- ],
- "vm-options": [
- "--enable_interpreter",
- "--compilation-counter-threshold=-1"
- ]
- }
- },
- "dartkb-interpret-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_interpreter",
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops"
- ],
- "vm-options": [
- "--enable_interpreter",
- "--compilation-counter-threshold=-1"
- ]
- }
- },
- "dartkb-mixed-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_mixed",
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops"
- ],
- "vm-options": [
- "--enable_interpreter"
- ]
- }
- },
- "dartkb-mixed-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_mixed",
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations"
- ],
- "vm-options": [
- "--enable_interpreter"
- ]
- }
- },
- "dartkb-interpret-strong-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_interpreter_nnbd",
- "enable-experiment": [
- "non-nullable"
- ],
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations",
- "--sound-null-safety"
- ],
- "vm-options": [
- "--enable_interpreter",
- "--compilation-counter-threshold=-1",
- "--sound-null-safety"
- ]
- }
- },
- "dartkb-interpret-strong-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_interpreter_nnbd",
- "enable-experiment": [
- "non-nullable"
- ],
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops",
- "--sound-null-safety"
- ],
- "vm-options": [
- "--enable_interpreter",
- "--compilation-counter-threshold=-1",
- "--sound-null-safety"
- ]
- }
- },
- "dartkb-mixed-strong-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_mixed_nnbd",
- "enable-experiment": [
- "non-nullable"
- ],
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops",
- "--sound-null-safety"
- ],
- "vm-options": [
- "--enable_interpreter",
- "--sound-null-safety"
- ]
- }
- },
- "dartkb-mixed-strong-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
- "options": {
- "builder-tag": "bytecode_mixed_nnbd",
- "enable-experiment": [
- "non-nullable"
- ],
- "gen-kernel-options": [
- "--gen-bytecode",
- "--drop-ast",
- "--bytecode-options=source-positions,annotations",
- "--sound-null-safety"
- ],
- "vm-options": [
- "--enable_interpreter",
- "--sound-null-safety"
- ]
- }
- },
"dartdevk-checked-(linux|mac|win)-(debug|product|release)-(chrome|firefox)": {
"options": {
"checked": true,
@@ -1219,59 +1058,6 @@
},
{
"builders": [
- "vm-dartkb-linux-release-x64",
- "vm-dartkb-linux-release-simarm64"
- ],
- "meta": {
- "description": "This configuration is used by the vm kbc builders."
- },
- "steps": [
- {
- "name": "build dart",
- "script": "tools/build.py",
- "arguments": [
- "--bytecode",
- "runtime"
- ]
- },
- {
- "name": "vm mixed mode tests",
- "arguments": [
- "-ndartkb-mixed-linux-${mode}-${arch}"
- ],
- "fileset": "vm-kernel",
- "shards": 4
- },
- {
- "name": "vm mixed mode co19 tests",
- "arguments": [
- "-ndartkb-mixed-linux-${mode}-${arch}",
- "co19_2"
- ],
- "fileset": "vm-kernel",
- "shards": 4
- },
- {
- "name": "vm interpreter tests",
- "arguments": [
- "-ndartkb-interpret-linux-${mode}-${arch}"
- ],
- "fileset": "vm-kernel",
- "shards": 4
- },
- {
- "name": "vm interpreter co19 tests",
- "arguments": [
- "-ndartkb-interpret-linux-${mode}-${arch}",
- "co19_2"
- ],
- "fileset": "vm-kernel",
- "shards": 4
- }
- ]
- },
- {
- "builders": [
"vm-canary-linux-debug"
],
"meta": {
@@ -3616,7 +3402,6 @@
"name": "build dart for simarm_x64",
"script": "tools/build.py",
"arguments": [
- "--bytecode",
"gen_snapshot"
]
},
@@ -3625,7 +3410,6 @@
"script": "tools/build.py",
"arguments": [
"--arch=simarm",
- "--bytecode",
"dart_precompiled_runtime",
"vm_platform"
]
diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh
index 920e30a..6029940 100755
--- a/tools/bots/try_benchmarks.sh
+++ b/tools/bots/try_benchmarks.sh
@@ -146,7 +146,6 @@
out/ReleaseIA32/vm_platform_strong.dill \
out/ReleaseIA32/gen/kernel_service.dill \
out/ReleaseIA32/dart-sdk \
- tools/dart2js/angular2_testing_deps \
out/ReleaseIA32/dart \
out/ReleaseIA32/gen_snapshot \
out/ReleaseIA32/gen_kernel_bytecode.dill \
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index b7276b8..d750f93 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -93,7 +93,7 @@
# default 'language' "category" with code generated for both CFE and Analyzer,
# while other categories can be tailored more specifically.
-current-version: '2.10.0'
+current-version: '2.11.0'
features:
non-nullable:
diff --git a/utils/bazel/kernel_worker.dart b/utils/bazel/kernel_worker.dart
index 194fe55..a056905 100644
--- a/utils/bazel/kernel_worker.dart
+++ b/utils/bazel/kernel_worker.dart
@@ -198,7 +198,9 @@
// compatible while we migrate existing clients of this tool.
var targetName =
(parsedArgs['target'] as String) ?? (summaryOnly ? 'ddc' : 'vm');
- var targetFlags = new TargetFlags(trackWidgetCreation: trackWidgetCreation);
+ var targetFlags = new TargetFlags(
+ trackWidgetCreation: trackWidgetCreation,
+ enableNullSafety: nnbdMode == fe.NnbdMode.Strong);
Target target;
switch (targetName) {
case 'vm':