Version 2.12.0-32.0.dev
Merge commit '4cd0926703de6e0c0505f1c6736fa77fa54b0254' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 041bc3f..24ce857 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -148,7 +148,7 @@
"name": "cli_util",
"rootUri": "../third_party/pkg/cli_util",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.12"
},
{
"name": "clock",
@@ -704,7 +704,7 @@
"name": "usage",
"rootUri": "../third_party/pkg/usage",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.12"
},
{
"name": "vector_math",
@@ -764,7 +764,7 @@
"name": "yaml",
"rootUri": "../third_party/pkg/yaml",
"packageUri": "lib/",
- "languageVersion": "2.4"
+ "languageVersion": "2.12"
}
]
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1ed2a0..23f93f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -100,19 +100,28 @@
* The top level `pub` executable has been deprecated. Use `dart pub` instead.
See [dart tool][].
* New command `dart pub add` that adds new dependencies to your `pubspec.yaml`.
-
+
And a corresponding `dart pub remove` that removes dependencies.
* New option `dart pub outdated --mode=null-safety` that will analyze your
dependencies for null-safety.
* `dart pub publish` will now check your pubspec keys for likely typos.
* New command `dart pub login` that logs in to pub.dev.
* The `--server` option to `dart pub publish` and `dart pub uploader` have been
- deprecated. Use `publish_to` in your `pubspec.yaml` or set the
+ deprecated. Use `publish_to` in your `pubspec.yaml` or set the
`$PUB_HOSTED_URL` environment variable.
[#44072]: https://github.com/dart-lang/sdk/issues/44072
[dart tool]: https://dart.dev/tools/dart-tool
+## 2.10.4 - 2020-11-12
+
+This is a patch release that fixes a crash in the Dart VM (issues [#43941][],
+[flutter/flutter#43620][], and [Dart-Code/Dart-Code#2814][]).
+
+[#43941]: https://github.com/dart-lang/sdk/issues/43941
+[flutter/flutter#43620]: https://github.com/flutter/flutter/issues/43620
+[Dart-Code/Dart-Code#2814]: https://github.com/Dart-Code/Dart-Code/issues/2814
+
## 2.10.3 - 2020-10-29
This is a patch release that fixes the following issues:
diff --git a/DEPS b/DEPS
index 1784f7a..a93ac4f 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
"browser-compat-data_tag": "v1.0.22",
"charcode_rev": "bcd8a12c315b7a83390e4865ad847ecd9344cba2",
"chrome_rev" : "19997",
- "cli_util_rev" : "335ed165887d0ec97c2a09173ebf22dcf56a6c4e",
+ "cli_util_rev" : "50cc840b146615899e97b892578848401b2028d5",
"clock_rev" : "a494269254ba978e7ef8f192c5f7fec3fc05b9d3",
"collection_rev": "e4bb038ce2d8e66fb15818aa40685c68d53692ab",
"convert_rev": "dd3bd28f63be7cb8ab961f38bc73229e4473b555",
@@ -118,7 +118,7 @@
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_rev": "b8dfe403fd8528fd14399dee3a6527b55802dd4d",
"linter_tag": "0.1.124",
- "logging_rev": "9d2a7fdd05b09bc06474881152b5baaf38fd1329",
+ "logging_rev": "e2f633b543ef89c54688554b15ca3d7e425b86a2",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"markdown_rev": "6f89681d59541ddb1cf3a58efbdaa2304ffc3f51",
"matcher_rev": "9cae8faa7868bf3a88a7ba45eb0bd128e66ac515",
@@ -159,14 +159,14 @@
"test_rev": "e37a93bbeae23b215972d1659ac865d71287ff6a",
"tflite_native_rev": "0.4.0+1",
"typed_data_tag": "f94fc57b8e8c0e4fe4ff6cfd8290b94af52d3719",
- "usage_tag": "3.4.0",
+ "usage_tag": "16fbfd90c58f16e016a295a880bc722d2547d2c9",
"vector_math_rev": "0c9f5d68c047813a6dcdeb88ba7a42daddf25025",
"watcher_rev": "64e254eba16f56d41f10d72c0b1cb24e130e1f8b",
"webdriver_rev": "5a8d6805d9cf8a3cbb4fcd64849b538b7491e50e",
"web_components_rev": "8f57dac273412a7172c8ade6f361b407e2e4ed02",
"web_socket_channel_rev": "490061ef0e22d3c8460ad2802f9948219365ad6b",
"WebCore_rev": "fb11e887f77919450e497344da570d780e078bc8",
- "yaml_rev": "e5de429147a6b0fcb7e8ddb3c8e4674dc5dd0ecc",
+ "yaml_rev": "925c406f8bdb06ce7935f0a7d03187b36c6b62d0",
"zlib_rev": "c44fb7248079cc3d5563b14b3f758aee60d6b415",
"crashpad_rev": "bf327d8ceb6a669607b0dbab5a83a275d03f99ed",
"minichromium_rev": "8d641e30a8b12088649606b912c2bc4947419ccc",
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
index 54b682a..3154306 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
@@ -3,12 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
/// An object used to provide context information for Dart assist contributors.
///
/// Clients may not extend, implement or mix-in this class.
abstract class DartAssistContext {
+ /// Return the instrumentation service used to report errors that prevent a
+ /// fix from being composed.
+ InstrumentationService get instrumentationService;
+
/// The resolution result in which assist operates.
ResolvedUnitResult get resolveResult;
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index ede6d26..4792bed 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -5,12 +5,17 @@
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
/// An object used to provide context information for [DartFixContributor]s.
///
/// Clients may not extend, implement or mix-in this class.
abstract class DartFixContext implements FixContext {
+ /// Return the instrumentation service used to report errors that prevent a
+ /// fix from being composed.
+ InstrumentationService get instrumentationService;
+
/// The resolution result in which fix operates.
ResolvedUnitResult get resolveResult;
diff --git a/pkg/analysis_server/lib/src/cider/fixes.dart b/pkg/analysis_server/lib/src/cider/fixes.dart
index 099287a..60f649e 100644
--- a/pkg/analysis_server/lib/src/cider/fixes.dart
+++ b/pkg/analysis_server/lib/src/cider/fixes.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/micro/resolve_file.dart';
import 'package:meta/meta.dart';
@@ -43,6 +44,7 @@
if (errorLine == requestLine) {
var workspace = DartChangeWorkspace([resolvedUnit.session]);
var context = DartFixContextImpl(
+ InstrumentationService.NULL_SERVICE,
workspace,
resolvedUnit,
error,
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 5c09be3..c37c64c 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -887,9 +887,9 @@
}
void _checkForPackagespecUpdate(String path, ContextInfo info) {
- // Check to see if this is the .packages file for this context and if so,
- // update the context's source factory.
- if (pathContext.basename(path) == PACKAGE_SPEC_NAME) {
+ // Check to see if this is `.dart_tool/package_config.json` or `.packages`
+ // file for this context and if so, update the context's source factory.
+ if (_isPackageConfigJsonFilePath(path) || _isDotPackagesFilePath(path)) {
var driver = info.analysisDriver;
if (driver == null) {
// I suspect that this happens as a result of a race condition: server
@@ -1249,6 +1249,9 @@
if (info.hasDependency(path)) {
_recomputeFolderDisposition(info);
}
+
+ _checkForPackagespecUpdate(path, info);
+
// maybe excluded globally
if (_isExcluded(path) ||
_isContainedInDotFolder(info.folder.path, path) ||
@@ -1283,7 +1286,7 @@
return;
}
}
- if (_isPackagespec(path)) {
+ if (_isDotPackagesFilePath(path)) {
// Check for a sibling pubspec.yaml file.
if (!resourceProvider
.getFile(pathContext.join(directoryPath, PUBSPEC_NAME))
@@ -1323,7 +1326,7 @@
return;
}
}
- if (_isPackagespec(path)) {
+ if (_isDotPackagesFilePath(path)) {
// Check for a sibling pubspec.yaml file.
if (!resourceProvider
.getFile(pathContext.join(directoryPath, PUBSPEC_NAME))
@@ -1352,7 +1355,6 @@
}
}
}
- _checkForPackagespecUpdate(path, info);
_checkForAnalysisOptionsUpdate(path, info);
_checkForDataFileUpdate(path, info);
_checkForPubspecUpdate(path, info);
@@ -1388,6 +1390,10 @@
/// to specify data-driven fixes.
bool _isDataFile(String path) => pathContext.basename(path) == dataFileName;
+ bool _isDotPackagesFilePath(String path) {
+ return pathContext.basename(path) == PACKAGE_SPEC_NAME;
+ }
+
/// Returns `true` if the given [path] is excluded by [excludedPaths].
bool _isExcluded(String path) => _isExcludedBy(excludedPaths, path);
@@ -1415,8 +1421,12 @@
bool _isManifest(String path) => pathContext.basename(path) == MANIFEST_NAME;
- bool _isPackagespec(String path) =>
- pathContext.basename(path) == PACKAGE_SPEC_NAME;
+ bool _isPackageConfigJsonFilePath(String path) {
+ var components = pathContext.split(path);
+ return components.length > 2 &&
+ components[components.length - 1] == 'package_config.json' &&
+ components[components.length - 2] == '.dart_tool';
+ }
bool _isPubspec(String path) => pathContext.basename(path) == PUBSPEC_NAME;
@@ -1477,8 +1487,13 @@
var builder = callbacks.createContextBuilder(info.folder);
var options = builder.getAnalysisOptions(contextRoot,
contextRoot: driver.contextRoot);
+ var packages = builder.createPackageMap(contextRoot);
var factory = builder.createSourceFactory(contextRoot);
- driver.configure(analysisOptions: options, sourceFactory: factory);
+ driver.configure(
+ analysisOptions: options,
+ packages: packages,
+ sourceFactory: factory,
+ );
callbacks.analysisOptionsUpdated(driver);
}
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index e2fc729..62a8d6a 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -106,7 +106,8 @@
}
var workspace = DartChangeWorkspace(server.currentSessions);
- var processor = BulkFixProcessor(workspace);
+ var processor =
+ BulkFixProcessor(server.instrumentationService, workspace);
String sdkPath;
var sdk = server.findSdk();
@@ -232,6 +233,7 @@
server.requestStatistics?.addItemTimeNow(request, 'resolvedUnit');
if (result != null) {
var context = DartAssistContextImpl(
+ server.instrumentationService,
DartChangeWorkspace(server.currentSessions),
result,
offset,
@@ -643,7 +645,8 @@
var errorLine = lineInfo.getLocation(error.offset).lineNumber;
if (errorLine == requestLine) {
var workspace = DartChangeWorkspace(server.currentSessions);
- var context = DartFixContextImpl(workspace, result, error, (name) {
+ var context = DartFixContextImpl(
+ server.instrumentationService, workspace, result, error, (name) {
var tracker = server.declarationsTracker;
var provider = TopLevelDeclarationsProvider(tracker);
return provider.get(
diff --git a/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart b/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart
index d15e724..b78a73b 100644
--- a/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/error/codes.dart';
/// A processor used by [EditDartFix] to manage [FixErrorTask]s.
@@ -45,6 +46,7 @@
Future<void> fixError(ResolvedUnitResult result, AnalysisError error) async {
final workspace = DartChangeWorkspace(listener.server.currentSessions);
final dartContext = DartFixContextImpl(
+ InstrumentationService.NULL_SERVICE,
workspace,
result,
error,
diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
index 6ab084c..870c33f 100644
--- a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
@@ -15,6 +15,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/lint/registry.dart';
@@ -34,6 +35,7 @@
declaration.name.name == elem.name) {
var processor = AssistProcessor(
DartAssistContextImpl(
+ InstrumentationService.NULL_SERVICE,
DartChangeWorkspace(listener.server.currentSessions),
result,
declaration.name.offset,
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 0e5a949..9d6fb0a 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
@@ -168,6 +168,7 @@
try {
var context = DartAssistContextImpl(
+ server.instrumentationService,
DartChangeWorkspace(server.currentSessions),
unit,
offset,
@@ -237,7 +238,8 @@
var errorLine = lineInfo.getLocation(error.offset).lineNumber - 1;
if (errorLine >= range.start.line && errorLine <= range.end.line) {
var workspace = DartChangeWorkspace(server.currentSessions);
- var context = DartFixContextImpl(workspace, unit, error, (name) {
+ var context = DartFixContextImpl(
+ server.instrumentationService, workspace, unit, error, (name) {
var tracker = server.declarationsTracker;
return TopLevelDeclarationsProvider(tracker).get(
unit.session.analysisContext,
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 717b6cd..039b503 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -156,8 +156,9 @@
case server.DeclarationKind.CONSTRUCTOR:
return const [lsp.SymbolKind.Constructor];
case server.DeclarationKind.ENUM:
- case server.DeclarationKind.ENUM_CONSTANT:
return const [lsp.SymbolKind.Enum];
+ case server.DeclarationKind.ENUM_CONSTANT:
+ return const [lsp.SymbolKind.EnumMember, lsp.SymbolKind.Enum];
case server.DeclarationKind.FIELD:
return const [lsp.SymbolKind.Field];
case server.DeclarationKind.FUNCTION:
@@ -380,8 +381,9 @@
case server.ElementKind.CONSTRUCTOR_INVOCATION:
return const [lsp.SymbolKind.Constructor];
case server.ElementKind.ENUM:
- case server.ElementKind.ENUM_CONSTANT:
return const [lsp.SymbolKind.Enum];
+ case server.ElementKind.ENUM_CONSTANT:
+ return const [lsp.SymbolKind.EnumMember, lsp.SymbolKind.Enum];
case server.ElementKind.EXTENSION:
return const [lsp.SymbolKind.Namespace];
case server.ElementKind.FIELD:
diff --git a/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart b/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
index 808cb44..2984122 100644
--- a/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/statement/statement_completion.dart
@@ -203,7 +203,24 @@
void _addReplaceEdit(SourceRange range, String text) {
var edit = SourceEdit(range.offset, range.length, text);
- doSourceChange_addElementEdit(change, unitElement, edit);
+ // TODO(brianwilkerson) The commented out function call has been inlined in
+ // order to work around a situation in which _complete_doStatement creates
+ // a conflicting edit that happens to work because of the order in which
+ // the edits are applied. The implementation needs to be cleaned up in
+ // order to prevent the conflicting edit from being generated.
+ // doSourceChange_addElementEdit(change, unitElement, edit);
+ var fileEdit = change.getFileEdit(unitElement.source.fullName);
+ if (fileEdit == null) {
+ fileEdit = SourceFileEdit(file, 0);
+ change.addFileEdit(fileEdit);
+ }
+ var edits = fileEdit.edits;
+ var length = edits.length;
+ var index = 0;
+ while (index < length && edits[index].offset > edit.offset) {
+ index++;
+ }
+ edits.insert(index, edit);
}
void _appendEmptyBraces(SourceBuilder sb, [bool needsExitMark = false]) {
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 50910b8..04dc79d 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -4,12 +4,16 @@
import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
/// The implementation of [DartAssistContext].
class DartAssistContextImpl implements DartAssistContext {
@override
+ final InstrumentationService instrumentationService;
+
+ @override
final ChangeWorkspace workspace;
@override
@@ -21,8 +25,8 @@
@override
final int selectionLength;
- DartAssistContextImpl(this.workspace, this.resolveResult,
- this.selectionOffset, this.selectionLength);
+ DartAssistContextImpl(this.instrumentationService, this.workspace,
+ this.resolveResult, this.selectionOffset, this.selectionLength);
}
/// An enumeration of possible assist kinds.
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 6f994e4..d304168 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -73,6 +73,7 @@
import 'package:analyzer_plugin/utilities/assist/assist.dart'
hide AssistContributor;
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
/// The computer for Dart assists.
class AssistProcessor extends BaseProcessor {
@@ -151,16 +152,16 @@
SurroundWith.newInstance,
];
- final DartAssistContext context;
+ final DartAssistContext assistContext;
final List<Assist> assists = <Assist>[];
- AssistProcessor(this.context)
+ AssistProcessor(this.assistContext)
: super(
- selectionOffset: context.selectionOffset,
- selectionLength: context.selectionLength,
- resolvedResult: context.resolveResult,
- workspace: context.workspace,
+ selectionOffset: assistContext.selectionOffset,
+ selectionLength: assistContext.selectionLength,
+ resolvedResult: assistContext.resolveResult,
+ workspace: assistContext.workspace,
);
Future<List<Assist>> compute() async {
@@ -241,36 +242,42 @@
if (!setupSuccess) {
return;
}
+
+ Future<void> compute(CorrectionProducer producer) async {
+ producer.configure(context);
+ var builder = ChangeBuilder(
+ workspace: context.workspace, eol: context.utils.endOfLine);
+ try {
+ await producer.compute(builder);
+ _addAssistFromBuilder(builder, producer.assistKind,
+ args: producer.assistArguments);
+ } on ConflictingEditException catch (exception, stackTrace) {
+ // Handle the exception by (a) not adding an assist based on the
+ // producer and (b) logging the exception.
+ assistContext.instrumentationService
+ .logException(exception, stackTrace);
+ }
+ }
+
for (var generator in generators) {
var ruleNames = lintRuleMap[generator] ?? {};
if (!_containsErrorCode(ruleNames)) {
var producer = generator();
- producer.configure(context);
-
- var builder = ChangeBuilder(
- workspace: context.workspace, eol: context.utils.endOfLine);
- await producer.compute(builder);
- _addAssistFromBuilder(builder, producer.assistKind,
- args: producer.assistArguments);
+ await compute(producer);
}
}
for (var multiGenerator in multiGenerators) {
var multiProducer = multiGenerator();
multiProducer.configure(context);
for (var producer in multiProducer.producers) {
- var builder = ChangeBuilder(
- workspace: context.workspace, eol: context.utils.endOfLine);
- producer.configure(context);
- await producer.compute(builder);
- _addAssistFromBuilder(builder, producer.assistKind,
- args: producer.assistArguments);
+ await compute(producer);
}
}
}
bool _containsErrorCode(Set<String> errorCodes) {
final fileOffset = node.offset;
- for (var error in context.resolveResult.errors) {
+ for (var error in assistContext.resolveResult.errors) {
final errorSource = error.source;
if (file == errorSource.fullName) {
if (fileOffset >= error.offset &&
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index dfece89..e739602 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -66,11 +66,13 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/exception/exception.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
/// A fix producer that produces changes to fix multiple diagnostics.
class BulkFixProcessor {
@@ -338,6 +340,9 @@
RemoveNonNullAssertion.newInstance,
};
+ /// The service used to report errors when building fixes.
+ final InstrumentationService instrumentationService;
+
/// Information about the workspace containing the libraries in which changes
/// will be produced.
final DartChangeWorkspace workspace;
@@ -348,7 +353,7 @@
/// Initialize a newly created processor to create fixes for diagnostics in
/// libraries in the [workspace].
- BulkFixProcessor(this.workspace) {
+ BulkFixProcessor(this.instrumentationService, this.workspace) {
builder = ChangeBuilder(workspace: workspace);
}
@@ -378,6 +383,7 @@
var analysisOptions = result.session.analysisContext.analysisOptions;
for (var unitResult in result.units) {
final fixContext = DartFixContextImpl(
+ instrumentationService,
workspace,
unitResult,
null,
@@ -415,7 +421,14 @@
Future<void> compute(CorrectionProducer producer) async {
producer.configure(context);
- await producer.compute(builder);
+ try {
+ var localBuilder = builder.copy();
+ await producer.compute(localBuilder);
+ builder = localBuilder;
+ } on ConflictingEditException {
+ // If a conflicting edit was added in [compute], then the [localBuilder]
+ // is discarded and we revert to the previous state of the builder.
+ }
}
var errorCode = diagnostic.errorCode;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart
index bc71685..8e20c54 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_required_keyword.dart
@@ -4,6 +4,8 @@
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -14,7 +16,25 @@
@override
Future<void> compute(ChangeBuilder builder) async {
await builder.addDartFileEdit(file, (builder) {
- builder.addSimpleInsertion(node.parent.offset, 'required ');
+ var insertOffset = node.parent.offset;
+
+ var parent = node.parent;
+ if (parent is FormalParameter) {
+ var metadata = parent.metadata;
+ // Check for redundant `@required` annotations.
+ if (metadata.isNotEmpty) {
+ for (var annotation in metadata) {
+ if (annotation.elementAnnotation.isRequired) {
+ var length = annotation.endToken.next.offset -
+ annotation.beginToken.offset;
+ builder.addDeletion(SourceRange(annotation.offset, length));
+ break;
+ }
+ }
+ insertOffset = metadata.endToken.next.offset;
+ }
+ }
+ builder.addSimpleInsertion(insertOffset, 'required ');
});
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index fe6cbc4..8bd57b2 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
@@ -115,6 +116,9 @@
/// The implementation of [DartFixContext].
class DartFixContextImpl implements DartFixContext {
@override
+ final InstrumentationService instrumentationService;
+
+ @override
final ChangeWorkspace workspace;
@override
@@ -126,8 +130,8 @@
final List<TopLevelDeclaration> Function(String name)
getTopLevelDeclarationsFunction;
- DartFixContextImpl(this.workspace, this.resolveResult, this.error,
- this.getTopLevelDeclarationsFunction);
+ DartFixContextImpl(this.instrumentationService, this.workspace,
+ this.resolveResult, this.error, this.getTopLevelDeclarationsFunction);
@override
List<TopLevelDeclaration> getTopLevelDeclarations(String name) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart
index 649597a..716c97e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_fragment_parser.dart
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/expression.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/variable_scope.dart';
import 'package:analyzer/error/listener.dart';
/// A parser for the textual representation of a code fragment.
@@ -12,18 +14,37 @@
/// The error reporter to which diagnostics will be reported.
final ErrorReporter errorReporter;
+ /// The scope in which variables can be looked up.
+ VariableScope variableScope;
+
/// The amount to be added to translate from offsets within the content to
/// offsets within the file.
int delta;
/// The tokens being parsed.
- List<_Token> tokens;
+ /* late */ List<_Token> tokens;
+
+ /// The index in the [tokens] of the next token to be consumed.
+ int currentIndex = 0;
/// The accessors that have been parsed.
List<Accessor> accessors = [];
/// Initialize a newly created parser to report errors to the [errorReporter].
- CodeFragmentParser(this.errorReporter);
+ CodeFragmentParser(this.errorReporter, {VariableScope scope})
+ : variableScope = scope ?? VariableScope(null, {});
+
+ /// Return the current token, or `null` if the end of the tokens has been
+ /// reached.
+ _Token get currentToken =>
+ currentIndex < tokens.length ? tokens[currentIndex] : null;
+
+ /// Advance to the next token.
+ void advance() {
+ if (currentIndex < tokens.length) {
+ currentIndex++;
+ }
+ }
/// Parse the [content] into a list of accessors. Add the [delta] to translate
/// from offsets within the content to offsets within the file.
@@ -51,6 +72,29 @@
return accessors;
}
+ /// Parse the [content] into a condition. Add the [delta] to translate
+ /// from offsets within the content to offsets within the file.
+ ///
+ /// <content> ::=
+ /// <logicalExpression>
+ Expression parseCondition(String content, int delta) {
+ this.delta = delta;
+ tokens = _CodeFragmentScanner(content, delta, errorReporter).scan();
+ if (tokens == null) {
+ // The error has already been reported.
+ return null;
+ }
+ currentIndex = 0;
+ var expression = _parseLogicalAndExpression();
+ if (currentIndex < tokens.length) {
+ var token = tokens[currentIndex];
+ errorReporter.reportErrorForOffset(TransformSetErrorCode.unexpectedToken,
+ token.offset + delta, token.length, [token.kind.displayName]);
+ return null;
+ }
+ return expression;
+ }
+
/// Return the token at the given [index] if it exists and if it has one of
/// the [validKinds]. Report an error and return `null` if those conditions
/// aren't met.
@@ -155,25 +199,113 @@
return tokens.length;
}
}
+
+ /// Parse a logical expression.
+ ///
+ /// <equalityExpression> ::=
+ /// <primaryExpression> (<comparisonOperator> <primaryExpression>)?
+ /// <comparisonOperator> ::=
+ /// '==' | '!='
+ Expression _parseEqualityExpression() {
+ var expression = _parsePrimaryExpression();
+ if (expression == null) {
+ return null;
+ }
+ if (currentIndex >= tokens.length) {
+ return expression;
+ }
+ var kind = currentToken.kind;
+ if (kind == _TokenKind.equal || kind == _TokenKind.notEqual) {
+ advance();
+ var operator =
+ kind == _TokenKind.equal ? Operator.equal : Operator.notEqual;
+ var rightOperand = _parsePrimaryExpression();
+ if (rightOperand == null) {
+ return null;
+ }
+ expression = BinaryExpression(expression, operator, rightOperand);
+ }
+ return expression;
+ }
+
+ /// Parse a logical expression.
+ ///
+ /// <logicalExpression> ::=
+ /// <equalityExpression> ('&&' <equalityExpression>)*
+ Expression _parseLogicalAndExpression() {
+ var expression = _parseEqualityExpression();
+ if (expression == null) {
+ return null;
+ }
+ if (currentIndex >= tokens.length) {
+ return expression;
+ }
+ var kind = currentToken.kind;
+ while (kind == _TokenKind.and) {
+ advance();
+ var rightOperand = _parseEqualityExpression();
+ if (rightOperand == null) {
+ return null;
+ }
+ expression = BinaryExpression(expression, Operator.and, rightOperand);
+ if (currentIndex >= tokens.length) {
+ return expression;
+ }
+ kind = currentToken.kind;
+ }
+ return expression;
+ }
+
+ /// Parse a logical expression.
+ ///
+ /// <primaryExpression> ::=
+ /// <identifier> | <string>
+ Expression _parsePrimaryExpression() {
+ var token = currentToken;
+ var kind = token.kind;
+ if (kind == _TokenKind.identifier) {
+ advance();
+ var variableName = token.lexeme;
+ var generator = variableScope.lookup(variableName);
+ if (generator == null) {
+ errorReporter.reportErrorForOffset(
+ TransformSetErrorCode.undefinedVariable,
+ token.offset + delta,
+ token.length,
+ [variableName]);
+ return null;
+ }
+ return VariableReference(generator);
+ } else if (kind == _TokenKind.string) {
+ advance();
+ var lexeme = token.lexeme;
+ var value = lexeme.substring(1, lexeme.length - 1);
+ return LiteralString(value);
+ }
+ errorReporter.reportErrorForOffset(TransformSetErrorCode.expectedPrimary,
+ token.offset + delta, token.length);
+ return null;
+ }
}
/// A scanner for the textual representation of a code fragment.
class _CodeFragmentScanner {
static final int $0 = '0'.codeUnitAt(0);
-
static final int $9 = '9'.codeUnitAt(0);
-
static final int $a = 'a'.codeUnitAt(0);
-
static final int $z = 'z'.codeUnitAt(0);
-
static final int $A = 'A'.codeUnitAt(0);
static final int $Z = 'Z'.codeUnitAt(0);
+
+ static final int ampersand = '&'.codeUnitAt(0);
+ static final int bang = '!'.codeUnitAt(0);
static final int closeSquareBracket = ']'.codeUnitAt(0);
static final int carriageReturn = '\r'.codeUnitAt(0);
+ static final int equal = '='.codeUnitAt(0);
static final int newline = '\n'.codeUnitAt(0);
static final int openSquareBracket = '['.codeUnitAt(0);
static final int period = '.'.codeUnitAt(0);
+ static final int singleQuote = "'".codeUnitAt(0);
static final int space = ' '.codeUnitAt(0);
/// The string being scanned.
@@ -195,8 +327,15 @@
/// Return the tokens in the content, or `null` if there is an error in the
/// content that prevents it from being scanned.
List<_Token> scan() {
- if (content.isEmpty) {}
var length = content.length;
+
+ int peekAt(int offset) {
+ if (offset > length) {
+ return -1;
+ }
+ return content.codeUnitAt(offset);
+ }
+
var offset = _skipWhitespace(0);
var tokens = <_Token>[];
while (offset < length) {
@@ -210,6 +349,33 @@
} else if (char == period) {
tokens.add(_Token(offset, _TokenKind.period, '.'));
offset++;
+ } else if (char == ampersand) {
+ if (peekAt(offset + 1) != ampersand) {
+ return _reportInvalidCharacter(offset);
+ }
+ tokens.add(_Token(offset, _TokenKind.and, '&&'));
+ offset += 2;
+ } else if (char == bang) {
+ if (peekAt(offset + 1) != equal) {
+ return _reportInvalidCharacter(offset);
+ }
+ tokens.add(_Token(offset, _TokenKind.notEqual, '!='));
+ offset += 2;
+ } else if (char == equal) {
+ if (peekAt(offset + 1) != equal) {
+ return _reportInvalidCharacter(offset);
+ }
+ tokens.add(_Token(offset, _TokenKind.equal, '=='));
+ offset += 2;
+ } else if (char == singleQuote) {
+ var start = offset;
+ offset++;
+ while (offset < length && content.codeUnitAt(offset) != singleQuote) {
+ offset++;
+ }
+ offset++;
+ tokens.add(
+ _Token(start, _TokenKind.string, content.substring(start, offset)));
} else if (_isLetter(char)) {
var start = offset;
offset++;
@@ -227,12 +393,7 @@
tokens.add(_Token(
start, _TokenKind.integer, content.substring(start, offset)));
} else {
- errorReporter.reportErrorForOffset(
- TransformSetErrorCode.invalidCharacter,
- offset + delta,
- 1,
- [content.substring(offset, offset + 1)]);
- return null;
+ return _reportInvalidCharacter(offset);
}
offset = _skipWhitespace(offset);
}
@@ -250,6 +411,13 @@
bool _isWhitespace(int char) =>
char == space || char == newline || char == carriageReturn;
+ /// Report the presence of an invalid character at the given [offset].
+ Null _reportInvalidCharacter(int offset) {
+ errorReporter.reportErrorForOffset(TransformSetErrorCode.invalidCharacter,
+ offset + delta, 1, [content.substring(offset, offset + 1)]);
+ return null;
+ }
+
/// Return the index of the first character at or after the given [offset]
/// that isn't a whitespace character.
int _skipWhitespace(int offset) {
@@ -284,26 +452,38 @@
/// An indication of the kind of a token.
enum _TokenKind {
+ and,
closeSquareBracket,
+ equal,
identifier,
integer,
+ notEqual,
openSquareBracket,
period,
+ string,
}
extension on _TokenKind {
String get displayName {
switch (this) {
+ case _TokenKind.and:
+ return "'&&'";
case _TokenKind.closeSquareBracket:
return "']'";
+ case _TokenKind.equal:
+ return "'=='";
case _TokenKind.identifier:
return 'an identifier';
case _TokenKind.integer:
return 'an integer';
+ case _TokenKind.notEqual:
+ return "'!='";
case _TokenKind.openSquareBracket:
return "'['";
case _TokenKind.period:
return "'.'";
+ case _TokenKind.string:
+ return 'a string';
}
return '';
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/expression.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/expression.dart
new file mode 100644
index 0000000..ef1e04c
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/expression.dart
@@ -0,0 +1,50 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
+
+/// A binary expression.
+class BinaryExpression extends Expression {
+ /// The left operand.
+ final Expression leftOperand;
+
+ /// The operator.
+ final Operator operator;
+
+ /// The right operand.
+ final Expression rightOperand;
+
+ /// Initialize a newly created binary expression consisting of the
+ /// [leftOperand], [operator], and [rightOperand].
+ BinaryExpression(this.leftOperand, this.operator, this.rightOperand);
+}
+
+/// An expression.
+abstract class Expression {}
+
+/// A literal string.
+class LiteralString extends Expression {
+ /// The value of the literal string.
+ final String value;
+
+ /// Initialize a newly created literal string to have the given [value].
+ LiteralString(this.value);
+}
+
+/// An operator used in a binary expression.
+enum Operator {
+ and,
+ equal,
+ notEqual,
+}
+
+/// A reference to a variable.
+class VariableReference extends Expression {
+ /// The generator used to generate the value of the variable.
+ final ValueGenerator generator;
+
+ /// Initialize a newly created variable reference to reference the variable
+ /// whose value is computed by the [generator].
+ VariableReference(this.generator);
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
index 7ea8635..f22360a 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -18,6 +18,12 @@
"The key '{0}' can't be used when '{1}' is also used.");
/**
+ * No parameters.
+ */
+ static const TransformSetErrorCode expectedPrimary = TransformSetErrorCode(
+ 'expected_primary', "Expected either an identifier or a string literal.");
+
+ /**
* Parameters:
* 0: the character that is invalid
*/
@@ -97,7 +103,14 @@
* 0: the missing key
*/
static const TransformSetErrorCode undefinedVariable = TransformSetErrorCode(
- 'undefined_variable', "The variable '{0}' is not defined.");
+ 'undefined_variable', "The variable '{0}' isn't defined.");
+
+ /**
+ * Parameters:
+ * 0: the token that was unexpectedly found
+ */
+ static const TransformSetErrorCode unexpectedToken =
+ TransformSetErrorCode('unexpected_token', "Didn't expect to find {0}.");
/**
* Parameters:
@@ -122,7 +135,7 @@
/**
* Parameters:
* 0: a description of the expected kind of token
- * 1: a description of the actial kind of token
+ * 1: a description of the actual kind of token
*/
static const TransformSetErrorCode wrongToken = TransformSetErrorCode(
'wrong_token', "Expected to find {0}, but found {1}.");
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/variable_scope.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/variable_scope.dart
new file mode 100644
index 0000000..4e5bd68
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/variable_scope.dart
@@ -0,0 +1,25 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
+
+/// A scope in which the generators associated with variables can be looked up.
+class VariableScope {
+ /// The outer scope in which this scope is nested.
+ final VariableScope outerScope;
+
+ /// A table mapping variable names to generators.
+ final Map<String, ValueGenerator> _generators;
+
+ /// Initialize a newly created variable scope defining the variables in the
+ /// [_generators] map. Any variables not defined locally will be looked up in
+ /// the [outerScope].
+ VariableScope(this.outerScope, this._generators);
+
+ /// Return the generator used to generate the value of the variable with the
+ /// given [variableName], or `null` if the variable is not defined.
+ ValueGenerator lookup(String variableName) {
+ return _generators[variableName] ?? outerScope?.lookup(variableName);
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 30ab805..881714d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -160,6 +160,7 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError, Element, ElementKind;
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart' hide FixContributor;
/// A function that can be executed to create a multi-correction producer.
@@ -209,13 +210,14 @@
// one.
// For each fix, put the fix into the HashMap.
for (var i = 0; i < allAnalysisErrors.length; i++) {
- final FixContext fixContextI = DartFixContextImpl(
+ final FixContext fixContext = DartFixContextImpl(
+ context.instrumentationService,
context.workspace,
context.resolveResult,
allAnalysisErrors[i],
(name) => [],
);
- var processorI = FixProcessor(fixContextI);
+ var processorI = FixProcessor(fixContext);
var fixesListI = await processorI.compute();
for (var f in fixesListI) {
if (!map.containsKey(f.kind)) {
@@ -227,11 +229,11 @@
}
// For each FixKind in the HashMap, union each list together, then return
- // the set of unioned Fixes.
+ // the set of unioned fixes.
var result = <Fix>[];
- map.forEach((FixKind kind, List<Fix> fixesListJ) {
- if (fixesListJ.first.kind.canBeAppliedTogether()) {
- var unionFix = _unionFixList(fixesListJ);
+ map.forEach((FixKind kind, List<Fix> fixesList) {
+ if (fixesList.first.kind.canBeAppliedTogether()) {
+ var unionFix = _unionFixList(fixesList);
if (unionFix != null) {
result.add(unionFix);
}
@@ -1134,9 +1136,15 @@
producer.configure(context);
var builder = ChangeBuilder(
workspace: context.workspace, eol: context.utils.endOfLine);
- await producer.compute(builder);
- _addFixFromBuilder(builder, producer.fixKind,
- args: producer.fixArguments);
+ try {
+ await producer.compute(builder);
+ _addFixFromBuilder(builder, producer.fixKind,
+ args: producer.fixArguments);
+ } on ConflictingEditException catch (exception, stackTrace) {
+ // Handle the exception by (a) not adding a fix based on the producer
+ // and (b) logging the exception.
+ fixContext.instrumentationService.logException(exception, stackTrace);
+ }
}
var errorCode = error.errorCode;
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 28ba464..a6b4251 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -23,6 +23,7 @@
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/util/glob.dart';
import 'package:linter/src/rules.dart';
@@ -1490,6 +1491,34 @@
});
}
+ Future<void> test_watch_modifyPackageConfigJson() {
+ var packageConfigPath = '$projPath/.dart_tool/package_config.json';
+ var filePath = convertPath('$projPath/bin/main.dart');
+
+ resourceProvider.newFile(packageConfigPath, '');
+ resourceProvider.newFile(filePath, 'library main;');
+
+ manager.setRoots(<String>[projPath], <String>[]);
+
+ var filePaths = callbacks.currentFilePaths;
+ expect(filePaths, hasLength(1));
+ expect(filePaths, contains(filePath));
+ expect(_currentPackageMap, isEmpty);
+
+ // update .dart_tool/package_config.json
+ callbacks.now++;
+ resourceProvider.modifyFile(
+ packageConfigPath,
+ (PackageConfigFileBuilder()..add(name: 'my', rootPath: '../'))
+ .toContent(toUriStr: toUriStr),
+ );
+
+ return pumpEventQueue().then((_) {
+ // verify new package info
+ expect(_currentPackageMap.keys, unorderedEquals(['my']));
+ });
+ }
+
Future<void> test_watch_modifyPackagespec() {
var packagesPath = convertPath('$projPath/.packages');
var filePath = convertPath('$projPath/bin/main.dart');
diff --git a/pkg/analysis_server/test/edit/bulk_fixes_test.dart b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
index 7f22771..0b79983 100644
--- a/pkg/analysis_server/test/edit/bulk_fixes_test.dart
+++ b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
@@ -150,6 +150,9 @@
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/44080')
Future<void> test_unnecessaryNew_collectionLiteral_overlap() async {
+ // The test case currently drops the 'new' but does not convert the code to
+ // use a set literal. The code is no longer mangled, but we need to run the
+ // BulkFixProcessor iteratively to solve the second case.
addAnalysisOptionsFile('''
linter:
rules:
diff --git a/pkg/analysis_server/test/lsp/document_symbols_test.dart b/pkg/analysis_server/test/lsp/document_symbols_test.dart
index f66964d..fa1e3e0 100644
--- a/pkg/analysis_server/test/lsp/document_symbols_test.dart
+++ b/pkg/analysis_server/test/lsp/document_symbols_test.dart
@@ -18,6 +18,67 @@
@reflectiveTest
class DocumentSymbolsTest extends AbstractLspAnalysisServerTest {
+ Future<void> test_enumMember_notSupported() async {
+ const content = '''
+ enum Theme {
+ light,
+ }
+ ''';
+ newFile(mainFilePath, content: content);
+ await initialize();
+
+ final result = await getDocumentSymbols(mainFileUri.toString());
+ final symbols = result.map(
+ (docsymbols) => throw 'Expected SymbolInformations, got DocumentSymbols',
+ (symbolInfos) => symbolInfos,
+ );
+ expect(symbols, hasLength(2));
+
+ final themeEnum = symbols[0];
+ expect(themeEnum.name, equals('Theme'));
+ expect(themeEnum.kind, equals(SymbolKind.Enum));
+ expect(themeEnum.containerName, isNull);
+
+ final enumValue = symbols[1];
+ expect(enumValue.name, equals('light'));
+ // EnumMember is not in the original LSP list, so unless the client explicitly
+ // advertises support, we will fall back to Enum.
+ expect(enumValue.kind, equals(SymbolKind.Enum));
+ expect(enumValue.containerName, 'Theme');
+ }
+
+ Future<void> test_enumMember_supported() async {
+ const content = '''
+ enum Theme {
+ light,
+ }
+ ''';
+ newFile(mainFilePath, content: content);
+ await initialize(
+ textDocumentCapabilities: withDocumentSymbolKinds(
+ emptyTextDocumentClientCapabilities,
+ [SymbolKind.Enum, SymbolKind.EnumMember],
+ ),
+ );
+
+ final result = await getDocumentSymbols(mainFileUri.toString());
+ final symbols = result.map(
+ (docsymbols) => throw 'Expected SymbolInformations, got DocumentSymbols',
+ (symbolInfos) => symbolInfos,
+ );
+ expect(symbols, hasLength(2));
+
+ final themeEnum = symbols[0];
+ expect(themeEnum.name, equals('Theme'));
+ expect(themeEnum.kind, equals(SymbolKind.Enum));
+ expect(themeEnum.containerName, isNull);
+
+ final enumValue = symbols[1];
+ expect(enumValue.name, equals('light'));
+ expect(enumValue.kind, equals(SymbolKind.EnumMember));
+ expect(enumValue.containerName, 'Theme');
+ }
+
Future<void> test_flat() async {
const content = '''
String topLevel = '';
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index a21044d..342e9f1 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -333,6 +333,17 @@
});
}
+ TextDocumentClientCapabilities withDocumentSymbolKinds(
+ TextDocumentClientCapabilities source,
+ List<SymbolKind> kinds,
+ ) {
+ return extendTextDocumentCapabilities(source, {
+ 'documentSymbol': {
+ 'symbolKind': {'valueSet': kinds.map((k) => k.toJson()).toList()}
+ }
+ });
+ }
+
TextDocumentClientCapabilities withHierarchicalDocumentSymbolSupport(
TextDocumentClientCapabilities source,
) {
diff --git a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
index 47f0b08..504dc74 100644
--- a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
+++ b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart
@@ -61,8 +61,7 @@
}
Future<void> _computeCompletion(int offset) async {
- var result = await session.getResolvedUnit(testFile);
- var context = StatementCompletionContext(result, offset);
+ var context = StatementCompletionContext(testAnalysisResult, offset);
var processor = StatementCompletionProcessor(context);
var completion = await processor.compute();
change = completion.change;
diff --git a/pkg/analysis_server/test/services/correction/change_test.dart b/pkg/analysis_server/test/services/correction/change_test.dart
index ea70891..90b2dd9 100644
--- a/pkg/analysis_server/test/services/correction/change_test.dart
+++ b/pkg/analysis_server/test/services/correction/change_test.dart
@@ -25,7 +25,7 @@
void test_addEdit() {
var change = SourceChange('msg');
var edit1 = SourceEdit(1, 2, 'a');
- var edit2 = SourceEdit(1, 2, 'b');
+ var edit2 = SourceEdit(4, 2, 'b');
expect(change.edits, hasLength(0));
change.addEdit('/a.dart', 0, edit1);
expect(change.edits, hasLength(1));
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 b6ac127..2235fe2 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/instrumentation/service.dart';
import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError;
@@ -192,6 +193,7 @@
Future<List<Assist>> _computeAssists() async {
var context = DartAssistContextImpl(
+ InstrumentationService.NULL_SERVICE,
workspace,
testAnalysisResult,
_offset,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
index 1f22076..d5b03dc 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_required_test.dart
@@ -45,7 +45,7 @@
@override
FixKind get kind => DartFixKind.ADD_REQUIRED2;
- Future<void> test_withAssert() async {
+ Future<void> test_nonNullable() async {
await resolveTestCode('''
void function({String param}) {}
''');
@@ -53,4 +53,124 @@
void function({required String param}) {}
''');
}
+
+ Future<void> test_withRequiredAnnotation() async {
+ writeTestPackageConfig(meta: true);
+
+ await resolveTestCode('''
+import 'package:meta/meta.dart';
+
+void function({@required String param}) {}
+''');
+ await assertHasFix('''
+import 'package:meta/meta.dart';
+
+void function({required String param}) {}
+''');
+ }
+
+ Future<void> test_withRequiredAnnotation_constructor() async {
+ writeTestPackageConfig(meta: true);
+
+ await resolveTestCode('''
+import 'package:meta/meta.dart';
+
+class A {
+ String foo;
+ A({@required this.foo});
+}
+''');
+ await assertHasFix('''
+import 'package:meta/meta.dart';
+
+class A {
+ String foo;
+ A({required this.foo});
+}
+''');
+ }
+
+ Future<void> test_withRequiredAnnotation_functionParam() async {
+ writeTestPackageConfig(meta: true);
+
+ await resolveTestCode('''
+import 'package:meta/meta.dart';
+
+void f({@required int g(String)}) { }
+''');
+ await assertHasFix('''
+import 'package:meta/meta.dart';
+
+void f({required int g(String)}) { }
+''');
+ }
+
+ Future<void> test_withRequiredAnnotationInList_first() async {
+ writeTestPackageConfig(meta: true);
+
+ await resolveTestCode('''
+import 'package:meta/meta.dart';
+
+class Foo {
+ const Foo();
+}
+
+const foo = Foo();
+
+void function({@required @foo String param}) {}
+''');
+ await assertHasFix('''
+import 'package:meta/meta.dart';
+
+class Foo {
+ const Foo();
+}
+
+const foo = Foo();
+
+void function({@foo required String param}) {}
+''');
+ }
+
+ Future<void> test_withRequiredAnnotationInList_last() async {
+ writeTestPackageConfig(meta: true);
+
+ await resolveTestCode('''
+import 'package:meta/meta.dart';
+
+class Foo {
+ const Foo();
+}
+
+const foo = Foo();
+
+void function({@foo @required String param}) {}
+''');
+ await assertHasFix('''
+import 'package:meta/meta.dart';
+
+class Foo {
+ const Foo();
+}
+
+const foo = Foo();
+
+void function({@foo required String param}) {}
+''');
+ }
+
+ Future<void> test_withRequiredAnnotationWithReason() async {
+ writeTestPackageConfig(meta: true);
+
+ await resolveTestCode('''
+import 'package:meta/meta.dart';
+
+void function({@Required('reason') String param}) {}
+''');
+ await assertHasFix('''
+import 'package:meta/meta.dart';
+
+void function({required String param}) {}
+''');
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
index de7282e..3e9e14c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/services/available_declarations.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -65,7 +66,8 @@
var analysisContext = contextFor(testFile);
tracker.addContext(analysisContext);
var changeBuilder =
- await BulkFixProcessor(workspace).fixErrors([analysisContext]);
+ await BulkFixProcessor(InstrumentationService.NULL_SERVICE, workspace)
+ .fixErrors([analysisContext]);
return changeBuilder.sourceChange;
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart
index 75e883e..75f13ff 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_fragment_parser_test.dart
@@ -5,6 +5,9 @@
import 'package:_fe_analyzer_shared/src/base/errors.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/accessor.dart';
import 'package:analysis_server/src/services/correction/fix/data_driven/code_fragment_parser.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/expression.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/variable_scope.dart';
import 'package:analyzer/error/listener.dart';
import 'package:matcher/matcher.dart';
import 'package:test/test.dart';
@@ -15,7 +18,8 @@
void main() {
defineReflectiveSuite(() {
- defineReflectiveTests(CodeFragmentParserTest);
+ defineReflectiveTests(AccessorsTest);
+ defineReflectiveTests(ConditionTest);
});
}
@@ -23,20 +27,36 @@
List<Accessor> assertErrors(
String content, List<ExpectedError> expectedErrors) {
var errorListener = GatheringErrorListener();
- var errorReporter = ErrorReporter(errorListener, MockSource());
- var accessors = CodeFragmentParser(errorReporter).parse(content, 0);
+ var accessors = _parser(errorListener).parse(content, 0);
errorListener.assertErrors(expectedErrors);
return accessors;
}
+ Expression assertErrorsInCondition(String content, List<String> variables,
+ List<ExpectedError> expectedErrors) {
+ var errorListener = GatheringErrorListener();
+ var expression =
+ _parser(errorListener, variables: variables).parseCondition(content, 0);
+ errorListener.assertErrors(expectedErrors);
+ return expression;
+ }
+
List<Accessor> assertNoErrors(String content) {
var errorListener = GatheringErrorListener();
- var errorReporter = ErrorReporter(errorListener, MockSource());
- var accessors = CodeFragmentParser(errorReporter).parse(content, 0);
+ var accessors = _parser(errorListener).parse(content, 0);
errorListener.assertNoErrors();
return accessors;
}
+ Expression assertNoErrorsInCondition(String content,
+ {List<String> variables}) {
+ var errorListener = GatheringErrorListener();
+ var expression =
+ _parser(errorListener, variables: variables).parseCondition(content, 0);
+ errorListener.assertNoErrors();
+ return expression;
+ }
+
ExpectedError error(ErrorCode code, int offset, int length,
{String message,
Pattern messageContains,
@@ -46,10 +66,23 @@
message: message,
messageContains: messageContains,
expectedContextMessages: contextMessages);
+
+ CodeFragmentParser _parser(GatheringErrorListener listener,
+ {List<String> variables}) {
+ var errorReporter = ErrorReporter(listener, MockSource());
+ var map = <String, ValueGenerator>{};
+ if (variables != null) {
+ for (var variableName in variables) {
+ map[variableName] = CodeFragment([]);
+ }
+ }
+ var scope = VariableScope(null, map);
+ return CodeFragmentParser(errorReporter, scope: scope);
+ }
}
@reflectiveTest
-class CodeFragmentParserTest extends AbstractCodeFragmentParserTest {
+class AccessorsTest extends AbstractCodeFragmentParserTest {
void test_arguments_arguments_arguments() {
var accessors = assertNoErrors('arguments[0].arguments[1].arguments[2]');
expect(accessors, hasLength(3));
@@ -83,3 +116,30 @@
expect(accessors[0], isA<TypeArgumentAccessor>());
}
}
+
+@reflectiveTest
+class ConditionTest extends AbstractCodeFragmentParserTest {
+ void test_and() {
+ var expression = assertNoErrorsInCondition("'a' != 'b' && 'c' != 'd'")
+ as BinaryExpression;
+ expect(expression.leftOperand, isA<BinaryExpression>());
+ expect(expression.operator, Operator.and);
+ expect(expression.rightOperand, isA<BinaryExpression>());
+ }
+
+ void test_equal() {
+ var expression = assertNoErrorsInCondition('a == b', variables: ['a', 'b'])
+ as BinaryExpression;
+ expect(expression.leftOperand, isA<VariableReference>());
+ expect(expression.operator, Operator.equal);
+ expect(expression.rightOperand, isA<VariableReference>());
+ }
+
+ void test_notEqual() {
+ var expression = assertNoErrorsInCondition("a != 'b'", variables: ['a'])
+ as BinaryExpression;
+ expect(expression.leftOperand, isA<VariableReference>());
+ expect(expression.operator, Operator.notEqual);
+ expect(expression.rightOperand, isA<LiteralString>());
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart
index ec8ac42..c1ee9bd 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/missing_token_test.dart
@@ -21,6 +21,12 @@
]);
}
+ void test_empty() {
+ assertErrors('', [
+ error(TransformSetErrorCode.missingToken, 0, 0),
+ ]);
+ }
+
void test_identifier_afterPeriod() {
assertErrors('arguments[2].', [
error(TransformSetErrorCode.missingToken, 12, 1),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart
index a047759..ed35ea9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/wrong_token_test.dart
@@ -9,12 +9,12 @@
void main() {
defineReflectiveSuite(() {
- defineReflectiveTests(MissingTokenTest);
+ defineReflectiveTests(WrongTokenTest);
});
}
@reflectiveTest
-class MissingTokenTest extends AbstractCodeFragmentParserTest {
+class WrongTokenTest extends AbstractCodeFragmentParserTest {
void test_closeBracket() {
assertErrors('arguments[2 3', [
error(TransformSetErrorCode.wrongToken, 12, 1),
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 b474c5a..321da9d 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
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
@@ -277,6 +278,7 @@
tracker.addContext(analysisContext);
var context = DartFixContextImpl(
+ InstrumentationService.NULL_SERVICE,
workspace,
testAnalysisResult,
error,
diff --git a/pkg/analysis_server/test/src/utilities/mock_packages.dart b/pkg/analysis_server/test/src/utilities/mock_packages.dart
index 2bfb8d4..1a34e4a 100644
--- a/pkg/analysis_server/test/src/utilities/mock_packages.dart
+++ b/pkg/analysis_server/test/src/utilities/mock_packages.dart
@@ -2,12 +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 'package:analysis_tool/package_root.dart' as package_root;
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import '../../utils/package_root.dart' as package_root;
-
/// Helper for copying files from "tests/mock_packages" to memory file system.
class MockPackages {
static final MockPackages instance = MockPackages._();
diff --git a/pkg/analysis_server/test/verify_sorted_test.dart b/pkg/analysis_server/test/verify_sorted_test.dart
index 858f7c4..b59ef2b 100644
--- a/pkg/analysis_server/test/verify_sorted_test.dart
+++ b/pkg/analysis_server/test/verify_sorted_test.dart
@@ -5,6 +5,7 @@
import 'dart:io';
import 'package:analysis_server/src/services/correction/sort_members.dart';
+import 'package:analysis_tool/package_root.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
@@ -13,8 +14,6 @@
import 'package:meta/meta.dart';
import 'package:test/test.dart';
-import 'utils/package_root.dart';
-
void main() {
group('analysis_server', () {
buildTestsForAnalysisServer();
diff --git a/pkg/analysis_server/test/verify_tests_test.dart b/pkg/analysis_server/test/verify_tests_test.dart
index 573eb05..73aa656 100644
--- a/pkg/analysis_server/test/verify_tests_test.dart
+++ b/pkg/analysis_server/test/verify_tests_test.dart
@@ -2,87 +2,42 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analysis_tool/package_root.dart' as package_root;
+import 'package:analysis_tool/verify_tests.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:path/path.dart' as path;
-import 'package:test/test.dart';
-
-import 'utils/package_root.dart' as package_root;
void main() {
var provider = PhysicalResourceProvider.INSTANCE;
var packageRoot = provider.pathContext.normalize(package_root.packageRoot);
- var analysisServerPath =
- provider.pathContext.join(packageRoot, 'analysis_server');
- var testDirPath = provider.pathContext.join(analysisServerPath, 'test');
- var mocksDirPath = provider.pathContext.join(testDirPath, 'mock_packages');
-
- var collection = AnalysisContextCollection(
- resourceProvider: provider,
- includedPaths: <String>[testDirPath],
- excludedPaths: <String>[mocksDirPath],
- );
- var contexts = collection.contexts;
- if (contexts.length != 1) {
- fail('The test directory contains multiple analysis contexts.');
- }
-
- buildTestsIn(
- contexts[0].currentSession, testDirPath, provider.getFolder(testDirPath));
+ var pathToAnalyze = provider.pathContext.join(packageRoot, 'analysis_server');
+ var testDirPath = provider.pathContext.join(pathToAnalyze, 'test');
+ _VerifyTests(testDirPath, excludedPaths: [
+ (provider.pathContext.join(testDirPath, 'mock_packages'))
+ ]).build();
}
-void buildTestsIn(
- AnalysisSession session, String testDirPath, Folder directory) {
- var testFileNames = <String>[];
- File testAllFile;
- var children = directory.getChildren();
- children.sort((first, second) => first.shortName.compareTo(second.shortName));
- for (var child in children) {
- if (child is Folder) {
- if (child.shortName != 'integration' &&
- child.getChildAssumingFile('test_all.dart').exists) {
- testFileNames.add('${child.shortName}/test_all.dart');
- }
- buildTestsIn(session, testDirPath, child);
- } else if (child is File) {
- var name = child.shortName;
- if (name == 'test_all.dart') {
- testAllFile = child;
- } else if (name.endsWith('_test.dart')) {
- testFileNames.add(name);
- }
+class _VerifyTests extends VerifyTests {
+ _VerifyTests(String testDirPath, {List<String> excludedPaths})
+ : super(testDirPath, excludedPaths: excludedPaths);
+
+ @override
+ bool isExpensive(Resource resource) => resource.shortName == 'integration';
+
+ @override
+ bool isOkAsAdditionalTestAllImport(Folder folder, String uri) {
+ if (folder.path == folder.provider.pathContext.join(testDirPath, 'lsp') &&
+ uri == '../src/lsp/lsp_packet_transformer_test.dart') {
+ // `lsp/test_all.dart` also runs this one test in `lsp/src` for
+ // convenience.
+ return true;
}
+ if (folder.path == testDirPath &&
+ uri == '../tool/spec/check_all_test.dart') {
+ // The topmost `test_all.dart` also runs this one test in `tool` for
+ // convenience.
+ return true;
+ }
+ return super.isOkAsAdditionalTestAllImport(folder, uri);
}
- var relativePath = path.relative(directory.path, from: testDirPath);
- test(relativePath, () {
- if (testFileNames.isEmpty) {
- return;
- }
- if (testAllFile == null) {
- fail('Missing "test_all.dart" in $relativePath');
- }
- var result = session.getParsedUnit(testAllFile.path);
- if (result.state != ResultState.VALID) {
- fail('Could not parse ${testAllFile.path}');
- }
- var importedFiles = <String>[];
- for (var directive in result.unit.directives) {
- if (directive is ImportDirective) {
- importedFiles.add(directive.uri.stringValue);
- }
- }
- var missingFiles = <String>[];
- for (var testFileName in testFileNames) {
- if (!importedFiles.contains(testFileName)) {
- missingFiles.add(testFileName);
- }
- }
- if (missingFiles.isNotEmpty) {
- fail('Tests missing from "test_all.dart": ${missingFiles.join(', ')}');
- }
- });
}
diff --git a/pkg/analysis_server/tool/completion_metrics/relevance_table_generator.dart b/pkg/analysis_server/tool/completion_metrics/relevance_table_generator.dart
index b746fb6..74ef351 100644
--- a/pkg/analysis_server/tool/completion_metrics/relevance_table_generator.dart
+++ b/pkg/analysis_server/tool/completion_metrics/relevance_table_generator.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/protocol_server.dart' show ElementKind;
import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
import 'package:analysis_server/src/utilities/flutter.dart';
+import 'package:analysis_tool/package_root.dart' as package_root;
import 'package:analysis_tool/tools.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/context_root.dart';
@@ -26,8 +27,6 @@
import 'package:args/args.dart';
import 'package:meta/meta.dart';
-import '../../test/utils/package_root.dart' as package_root;
-
/// Compute metrics to determine whether they should be used to compute a
/// relevance score for completion suggestions.
Future<void> main(List<String> args) async {
diff --git a/pkg/analysis_server_client/pubspec.yaml b/pkg/analysis_server_client/pubspec.yaml
index 9ee4b0e..465884d 100644
--- a/pkg/analysis_server_client/pubspec.yaml
+++ b/pkg/analysis_server_client/pubspec.yaml
@@ -15,4 +15,6 @@
path: ../analyzer
analysis_server:
path: ../analysis_server
+ analysis_tool:
+ path: ../analysis_tool
test: ^1.14.2
diff --git a/pkg/analysis_server_client/test/utils/package_root.dart b/pkg/analysis_server_client/test/utils/package_root.dart
deleted file mode 100644
index e8befb2..0000000
--- a/pkg/analysis_server_client/test/utils/package_root.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2017, 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';
-
-import 'package:path/path.dart' as pathos;
-
-/// Returns a path to the directory containing source code for packages such as
-/// kernel, front_end, and analyzer.
-String get packageRoot {
- // If the package root directory is specified on the command line using
- // -DpkgRoot=..., use it.
- const pkgRootVar =
- bool.hasEnvironment('pkgRoot') ? String.fromEnvironment('pkgRoot') : null;
- if (pkgRootVar != null) {
- var path = pathos.join(Directory.current.path, pkgRootVar);
- if (!path.endsWith(pathos.separator)) path += pathos.separator;
- return path;
- }
- // Otherwise try to guess based on the script path.
- var scriptPath = pathos.fromUri(Platform.script);
- var parts = pathos.split(scriptPath);
- var pkgIndex = parts.indexOf('pkg');
- if (pkgIndex != -1) {
- return pathos.joinAll(parts.sublist(0, pkgIndex + 1)) + pathos.separator;
- }
- throw StateError('Unable to find sdk/pkg/ in $scriptPath');
-}
diff --git a/pkg/analysis_server_client/test/verify_sorted_test.dart b/pkg/analysis_server_client/test/verify_sorted_test.dart
index 88f936f..66a848a 100644
--- a/pkg/analysis_server_client/test/verify_sorted_test.dart
+++ b/pkg/analysis_server_client/test/verify_sorted_test.dart
@@ -5,6 +5,7 @@
import 'dart:io';
import 'package:analysis_server/src/services/correction/sort_members.dart';
+import 'package:analysis_tool/package_root.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
@@ -12,8 +13,6 @@
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:test/test.dart';
-import 'utils/package_root.dart';
-
void main() {
var provider = PhysicalResourceProvider.INSTANCE;
var normalizedRoot = provider.pathContext.normalize(packageRoot);
diff --git a/pkg/analysis_server/test/utils/package_root.dart b/pkg/analysis_tool/lib/package_root.dart
similarity index 100%
rename from pkg/analysis_server/test/utils/package_root.dart
rename to pkg/analysis_tool/lib/package_root.dart
diff --git a/pkg/analysis_tool/lib/verify_tests.dart b/pkg/analysis_tool/lib/verify_tests.dart
new file mode 100644
index 0000000..ca6fe74
--- /dev/null
+++ b/pkg/analysis_tool/lib/verify_tests.dart
@@ -0,0 +1,137 @@
+// 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/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+/// Helper class to test that `test_all.dart` files are properly set up in the
+/// `analyzer` package (and related packages).
+class VerifyTests {
+ /// Path to the package's `test` subdirectory.
+ final String testDirPath;
+
+ /// Paths to exclude from analysis completely.
+ final List<String> excludedPaths;
+
+ VerifyTests(this.testDirPath, {this.excludedPaths});
+
+ /// Build tests.
+ void build() {
+ var provider = PhysicalResourceProvider.INSTANCE;
+ var collection = AnalysisContextCollection(
+ resourceProvider: provider,
+ includedPaths: <String>[testDirPath],
+ excludedPaths: excludedPaths);
+ var contexts = collection.contexts;
+ if (contexts.length != 1) {
+ fail('The test directory contains multiple analysis contexts.');
+ }
+
+ _buildTestsIn(contexts[0].currentSession, testDirPath,
+ provider.getFolder(testDirPath));
+ }
+
+ /// May be overridden in a derived class to indicate whether the test file or
+ /// directory indicated by [resource] is so expensive to run that it shouldn't
+ /// be included in `test_all.dart` files.
+ ///
+ /// Default behavior is not to consider any test files or directories
+ /// expensive.
+ bool isExpensive(Resource resource) => false;
+
+ /// May be overridden in a derived class to indicate whether it is ok for a
+ /// `test_all.dart` file in [folder] to import [uri], even if there is no
+ /// corresponding test file inside [folder].
+ ///
+ /// Default behavior is to allow imports of test framework URIs.
+ bool isOkAsAdditionalTestAllImport(Folder folder, String uri) => const [
+ 'package:test/test.dart',
+ 'package:test_reflective_loader/test_reflective_loader.dart'
+ ].contains(uri);
+
+ /// May be overridden in a derived class to indicate whether it is ok for
+ /// a `test_all.dart` file to be missing from [folder].
+ ///
+ /// Default beahvior is not to allow `test_all.dart` to be missing from any
+ /// folder.
+ bool isOkForTestAllToBeMissing(Folder folder) => false;
+
+ void _buildTestsIn(
+ AnalysisSession session, String testDirPath, Folder directory) {
+ var testFileNames = <String>[];
+ File testAllFile;
+ var children = directory.getChildren();
+ children
+ .sort((first, second) => first.shortName.compareTo(second.shortName));
+ for (var child in children) {
+ if (child is Folder) {
+ if (child.getChildAssumingFile('test_all.dart').exists &&
+ !isExpensive(child)) {
+ testFileNames.add('${child.shortName}/test_all.dart');
+ }
+ _buildTestsIn(session, testDirPath, child);
+ } else if (child is File) {
+ var name = child.shortName;
+ if (name == 'test_all.dart') {
+ testAllFile = child;
+ } else if (name.endsWith('_test.dart') && !isExpensive(child)) {
+ testFileNames.add(name);
+ }
+ }
+ }
+ var relativePath = path.relative(directory.path, from: testDirPath);
+ test(relativePath, () {
+ if (testFileNames.isEmpty) {
+ return;
+ }
+ if (testAllFile == null) {
+ if (!isOkForTestAllToBeMissing(directory)) {
+ fail('Missing "test_all.dart" in $relativePath');
+ } else {
+ // Ok that the `test_all.dart` file is missing; there's nothing else to
+ // check.
+ return;
+ }
+ }
+ if (isOkForTestAllToBeMissing(directory)) {
+ fail('Found "test_all.dart" in $relativePath but did not expect one');
+ }
+ var result = session.getParsedUnit(testAllFile.path);
+ if (result.state != ResultState.VALID) {
+ fail('Could not parse ${testAllFile.path}');
+ }
+ var importedFiles = <String>[];
+ for (var directive in result.unit.directives) {
+ if (directive is ImportDirective) {
+ importedFiles.add(directive.uri.stringValue);
+ }
+ }
+ var missingFiles = <String>[];
+ for (var testFileName in testFileNames) {
+ if (!importedFiles.contains(testFileName)) {
+ missingFiles.add(testFileName);
+ }
+ }
+ if (missingFiles.isNotEmpty) {
+ fail('Tests missing from "test_all.dart": ${missingFiles.join(', ')}');
+ }
+ var extraImports = <String>[];
+ for (var importedFile in importedFiles) {
+ if (!testFileNames.contains(importedFile) &&
+ !isOkAsAdditionalTestAllImport(directory, importedFile)) {
+ extraImports.add(importedFile);
+ }
+ }
+ if (extraImports.isNotEmpty) {
+ fail('Extra tests in "test_all.dart": ${extraImports.join(', ')}');
+ }
+ });
+ }
+}
diff --git a/pkg/analysis_tool/pubspec.yaml b/pkg/analysis_tool/pubspec.yaml
index 32199b3..f4763fd 100644
--- a/pkg/analysis_tool/pubspec.yaml
+++ b/pkg/analysis_tool/pubspec.yaml
@@ -6,5 +6,7 @@
sdk: '>=2.1.0 <3.0.0'
dependencies:
+ analyzer: any
html: any
path: any
+ test: any
diff --git a/pkg/analyzer/lib/dart/analysis/features.dart b/pkg/analyzer/lib/dart/analysis/features.dart
index e086608..5390ffa 100644
--- a/pkg/analyzer/lib/dart/analysis/features.dart
+++ b/pkg/analyzer/lib/dart/analysis/features.dart
@@ -32,6 +32,10 @@
/// Feature information for the triple-shift operator.
static final triple_shift = ExperimentalFeatures.triple_shift;
+ /// Feature information for non-function type aliases.
+ static final nonfunction_type_aliases =
+ ExperimentalFeatures.nonfunction_type_aliases;
+
/// Feature information for variance.
static final variance = ExperimentalFeatures.variance;
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 7ee7034..9f49d07 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -2933,12 +2933,18 @@
set equals(Token token);
/// Return the type of function being defined by the alias.
+ ///
+ /// When the non-function type aliases feature is enabled and the denoted
+ /// type is not a [GenericFunctionType], return `null`.
GenericFunctionType get functionType;
/// Set the type of function being defined by the alias to the given
/// [functionType].
set functionType(GenericFunctionType functionType);
+ /// Return the type being defined by the alias.
+ TypeAnnotation get type;
+
/// Return the type parameters for the function type, or `null` if the
/// function type does not have any type parameters.
TypeParameterList get typeParameters;
diff --git a/pkg/analyzer/lib/dart/ast/ast_factory.dart b/pkg/analyzer/lib/dart/ast/ast_factory.dart
index 65b253e..4dcba21 100644
--- a/pkg/analyzer/lib/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/dart/ast/ast_factory.dart
@@ -511,7 +511,7 @@
SimpleIdentifier name,
TypeParameterList typeParameters,
Token equals,
- GenericFunctionType functionType,
+ TypeAnnotation type,
Token semicolon);
/// Returns a newly created import show combinator.
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 428ee8a..9a4bcad 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -19,7 +19,6 @@
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -1012,13 +1011,15 @@
Token get endToken => _block.endToken;
@override
- bool get isAsynchronous => keyword != null && keyword.lexeme == Parser.ASYNC;
+ bool get isAsynchronous =>
+ keyword != null && keyword.lexeme == Keyword.ASYNC.lexeme;
@override
bool get isGenerator => star != null;
@override
- bool get isSynchronous => keyword == null || keyword.lexeme != Parser.ASYNC;
+ bool get isSynchronous =>
+ keyword == null || keyword.lexeme != Keyword.ASYNC.lexeme;
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitBlockFunctionBody(this);
@@ -5363,6 +5364,9 @@
/// metadata 'typedef' [SimpleIdentifier] [TypeParameterList]? =
/// [FunctionType] ';'
class GenericTypeAliasImpl extends TypeAliasImpl implements GenericTypeAlias {
+ /// The type being defined by the alias.
+ TypeAnnotationImpl _type;
+
/// The type parameters for the function type, or `null` if the function
/// type does not have any type parameters.
TypeParameterListImpl _typeParameters;
@@ -5370,9 +5374,6 @@
@override
Token equals;
- /// The type of function being defined by the alias.
- GenericFunctionTypeImpl _functionType;
-
/// Returns a newly created generic type alias. Either or both of the
/// [comment] and [metadata] can be `null` if the variable list does not have
/// the corresponding attribute. The [typeParameters] can be `null` if there
@@ -5384,11 +5385,11 @@
SimpleIdentifierImpl name,
TypeParameterListImpl typeParameters,
this.equals,
- GenericFunctionTypeImpl functionType,
+ TypeAnnotationImpl type,
Token semicolon)
: super(comment, metadata, typedefToken, name, semicolon) {
_typeParameters = _becomeParentOf(typeParameters);
- _functionType = _becomeParentOf(functionType);
+ _type = _becomeParentOf(type);
}
@override
@@ -5398,20 +5399,31 @@
..add(name)
..add(_typeParameters)
..add(equals)
- ..add(_functionType);
+ ..add(_type);
@override
Element get declaredElement => name.staticElement;
+ /// The type of function being defined by the alias.
+ ///
+ /// If the non-function type aliases feature is enabled, a type alias may have
+ /// a [_type] which is not a [GenericFunctionTypeImpl]. In that case `null`
+ /// is returned.
@override
- GenericFunctionType get functionType => _functionType;
+ GenericFunctionType get functionType {
+ var t = _type;
+ return t is GenericFunctionTypeImpl ? t : null;
+ }
@override
set functionType(GenericFunctionType functionType) {
- _functionType = _becomeParentOf(functionType as GenericFunctionTypeImpl);
+ _type = _becomeParentOf(functionType as TypeAnnotationImpl);
}
@override
+ TypeAnnotation get type => _type;
+
+ @override
TypeParameterList get typeParameters => _typeParameters;
@override
@@ -5429,7 +5441,7 @@
super.visitChildren(visitor);
name?.accept(visitor);
_typeParameters?.accept(visitor);
- _functionType?.accept(visitor);
+ _type?.accept(visitor);
}
}
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 8e1fd6a..f1a91b6 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -575,10 +575,10 @@
SimpleIdentifier name,
TypeParameterList typeParameters,
Token equals,
- GenericFunctionType functionType,
+ TypeAnnotation type,
Token semicolon) =>
GenericTypeAliasImpl(comment, metadata, typedefKeyword, name,
- typeParameters, equals, functionType, semicolon);
+ typeParameters, equals, type, semicolon);
@override
HideCombinator hideCombinator(
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index ccfec81..5204bac 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -128,6 +128,9 @@
/// `true` if triple-shift behavior is enabled
final bool enableTripleShift;
+ /// `true` if nonfunction-type-aliases behavior is enabled
+ final bool enableNonFunctionTypeAliases;
+
/// `true` if variance behavior is enabled
final bool enableVariance;
@@ -143,6 +146,8 @@
enableControlFlowCollections =
_featureSet.isEnabled(Feature.control_flow_collections),
enableTripleShift = _featureSet.isEnabled(Feature.triple_shift),
+ enableNonFunctionTypeAliases =
+ _featureSet.isEnabled(Feature.nonfunction_type_aliases),
enableVariance = _featureSet.isEnabled(Feature.variance),
uri = uri ?? fileUri;
@@ -1532,10 +1537,8 @@
SimpleIdentifier name = pop();
List<Annotation> metadata = pop();
Comment comment = _findComment(metadata, typedefKeyword);
- if (type is! GenericFunctionType) {
- // This error is also reported in the OutlineBuilder.
+ if (type is! GenericFunctionType && !enableNonFunctionTypeAliases) {
handleRecoverableError(messageTypedefNotFunction, equals, equals);
- type = null;
}
declarations.add(ast.genericTypeAlias(
comment,
@@ -1544,7 +1547,7 @@
name,
templateParameters,
equals,
- type as GenericFunctionType,
+ type,
semicolon));
}
}
@@ -3042,8 +3045,11 @@
// Determine if this is a set or map based on type args and content
final typeArgCount = typeArguments?.arguments?.length;
- bool isSet =
- typeArgCount == 1 ? true : typeArgCount != null ? false : null;
+ bool isSet = typeArgCount == 1
+ ? true
+ : typeArgCount != null
+ ? false
+ : null;
isSet ??= hasSetEntry;
// Build the set or map
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 8a09582..5864421 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -443,7 +443,7 @@
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- ClassElementImpl enclosingClass = _resolver.enclosingClass;
+ var enclosingClass = _resolver.enclosingClass;
if (enclosingClass == null) {
// TODO(brianwilkerson) Report this error.
return;
@@ -646,7 +646,7 @@
element = _resolver.toLegacyElement(element);
if (element is PropertyAccessorElement && identifier.inSetterContext()) {
- PropertyAccessorElement setter = lookupResult.setter;
+ var setter = lookupResult.setter;
if (setter == null) {
//
// Check to see whether there might be a locally defined getter and
@@ -734,7 +734,8 @@
/// Resolve each of the annotations in the given list of [annotations].
static void _resolveAnnotations(NodeList<Annotation> annotations) {
for (Annotation annotation in annotations) {
- ElementAnnotationImpl elementAnnotation = annotation.elementAnnotation;
+ var elementAnnotation =
+ annotation.elementAnnotation as ElementAnnotationImpl;
elementAnnotation.element = annotation.element;
}
}
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index f1baaf4..e0368a4 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -386,7 +386,7 @@
FeatureSet get contextFeatures => _contextFeatures;
set contextFeatures(FeatureSet featureSet) {
- _contextFeatures = featureSet;
+ _contextFeatures = featureSet as ExperimentStatus;
nonPackageFeatureSet = featureSet;
}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 98b30f2..b1123a3 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -22,6 +22,7 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
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/scope.dart';
import 'package:analyzer/src/dart/resolver/variance.dart';
@@ -240,8 +241,8 @@
_isInStaticVariableDeclaration = false;
_isInConstructorInitializer = false;
_intType = _typeProvider.intType;
- _typeSystem = _currentLibrary.typeSystem;
- _options = _currentLibrary.context.analysisOptions;
+ _typeSystem = _currentLibrary.typeSystem as TypeSystemImpl;
+ _options = _currentLibrary.context.analysisOptions as AnalysisOptionsImpl;
_typeArgumentsVerifier =
TypeArgumentsVerifier(_options, _currentLibrary, _errorReporter);
_constructorFieldsVerifier = ConstructorFieldsVerifier(
@@ -249,7 +250,7 @@
errorReporter: _errorReporter,
);
_returnTypeVerifier = ReturnTypeVerifier(
- typeProvider: _typeProvider,
+ typeProvider: _typeProvider as TypeProviderImpl,
typeSystem: _typeSystem,
errorReporter: _errorReporter,
);
@@ -268,7 +269,7 @@
assert(_enclosingClass == null);
assert(_enclosingEnum == null);
assert(_enclosingExecutable.element == null);
- _enclosingClass = classElement;
+ _enclosingClass = classElement as ClassElementImpl;
}
/// The language team is thinking about adding abstract fields, or external
@@ -329,14 +330,14 @@
_checkForArgumentTypeNotAssignableForArgument(rhs);
}
if (operatorType == TokenType.QUESTION_QUESTION_EQ) {
- _checkForDeadNullCoalesce(node.readType, node.rightHandSide);
+ _checkForDeadNullCoalesce(node.readType as TypeImpl, node.rightHandSide);
}
_checkForAssignmentToFinal(lhs);
if (lhs is IndexExpression) {
_checkIndexExpressionIndex(
lhs.index,
- readElement: node.readElement,
- writeElement: node.writeElement,
+ readElement: node.readElement as ExecutableElement,
+ writeElement: node.writeElement as ExecutableElement,
);
}
super.visitAssignmentExpression(node);
@@ -371,7 +372,8 @@
}
if (type == TokenType.QUESTION_QUESTION) {
- _checkForDeadNullCoalesce(node.leftOperand.staticType, node.rightOperand);
+ _checkForDeadNullCoalesce(
+ node.leftOperand.staticType as TypeImpl, node.rightOperand);
}
_checkForUseOfVoidResult(node.leftOperand);
@@ -427,7 +429,7 @@
ClassElementImpl outerClass = _enclosingClass;
try {
_isInNativeClass = node.nativeClause != null;
- _enclosingClass = node.declaredElement;
+ _enclosingClass = node.declaredElement as ClassElementImpl;
List<ClassMember> members = node.members;
_duplicateDefinitionVerifier.checkClass(node);
@@ -465,7 +467,7 @@
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
ClassElementImpl outerClassElement = _enclosingClass;
try {
- _enclosingClass = node.declaredElement;
+ _enclosingClass = node.declaredElement as ClassElementImpl;
_checkClassInheritance(
node, node.superclass, node.withClause, node.implementsClause);
_checkForMainFunction(node.name);
@@ -567,7 +569,7 @@
@override
void visitExportDirective(ExportDirective node) {
- ExportElement exportElement = node.element;
+ var exportElement = node.element as ExportElement;
if (exportElement != null) {
LibraryElement exportedLibrary = exportElement.exportedLibrary;
_checkForAmbiguousExport(node, exportElement, exportedLibrary);
@@ -711,7 +713,8 @@
GetterSetterTypesVerifier(
typeSystem: _typeSystem,
errorReporter: _errorReporter,
- ).checkGetter(node.name, node.declaredElement);
+ ).checkGetter(
+ node.name, node.declaredElement as PropertyAccessorElement);
}
if (node.isSetter) {
FunctionExpression functionExpression = node.functionExpression;
@@ -808,7 +811,8 @@
_checkForBuiltInIdentifierAsName(
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
_checkForMainFunction(node.name);
- _checkForTypeAliasCannotReferenceItself(node, node.declaredElement);
+ _checkForTypeAliasCannotReferenceItself(
+ node, node.declaredElement as FunctionTypeAliasElement);
super.visitGenericTypeAlias(node);
}
@@ -820,7 +824,7 @@
@override
void visitImportDirective(ImportDirective node) {
- ImportElement importElement = node.element;
+ var importElement = node.element as ImportElement;
if (node.prefix != null) {
_checkForBuiltInIdentifierAsName(
node.prefix, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_PREFIX_NAME);
@@ -910,7 +914,8 @@
GetterSetterTypesVerifier(
typeSystem: _typeSystem,
errorReporter: _errorReporter,
- ).checkGetter(node.name, node.declaredElement);
+ ).checkGetter(
+ node.name, node.declaredElement as PropertyAccessorElement);
}
if (node.isSetter) {
_checkForWrongNumberOfParametersForSetter(node.name, node.parameters);
@@ -952,7 +957,7 @@
// TODO(scheglov) Verify for all mixin errors.
ClassElementImpl outerClass = _enclosingClass;
try {
- _enclosingClass = node.declaredElement;
+ _enclosingClass = node.declaredElement as ClassElementImpl;
List<ClassMember> members = node.members;
_duplicateDefinitionVerifier.checkMixin(node);
@@ -1009,8 +1014,8 @@
if (operand is IndexExpression) {
_checkIndexExpressionIndex(
operand.index,
- readElement: node.readElement,
- writeElement: node.writeElement,
+ readElement: node.readElement as ExecutableElement,
+ writeElement: node.writeElement as ExecutableElement,
);
}
super.visitPostfixExpression(node);
@@ -1042,8 +1047,8 @@
if (operand is IndexExpression) {
_checkIndexExpressionIndex(
operand.index,
- readElement: node.readElement,
- writeElement: node.writeElement,
+ readElement: node.readElement as ExecutableElement,
+ writeElement: node.writeElement as ExecutableElement,
);
}
super.visitPrefixExpression(node);
@@ -1570,7 +1575,8 @@
}) {
DartType staticParameterType = parameter?.type;
if (promoteParameterToNullable && staticParameterType != null) {
- staticParameterType = _typeSystem.makeNullable(staticParameterType);
+ staticParameterType =
+ _typeSystem.makeNullable(staticParameterType as TypeImpl);
}
_checkForArgumentTypeNotAssignableWithExpectedTypes(argument,
staticParameterType, CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE);
@@ -3295,7 +3301,7 @@
/// the [mixinIndex] position in the mixins list are satisfied by the
/// [_enclosingClass], or a previous mixin.
bool _checkForMixinSuperclassConstraints(int mixinIndex, TypeName mixinName) {
- InterfaceType mixinType = mixinName.type;
+ InterfaceType mixinType = mixinName.type as InterfaceType;
for (var constraint in mixinType.superclassConstraints) {
var superType = _enclosingClass.supertype as InterfaceTypeImpl;
if (_currentLibrary.isNonNullableByDefault) {
@@ -3330,7 +3336,7 @@
/// implementations of all the super-invoked members of the [mixinElement].
bool _checkForMixinSuperInvokedMembers(int mixinIndex, TypeName mixinName,
ClassElement mixinElement, InterfaceType mixinType) {
- ClassElementImpl mixinElementImpl = mixinElement;
+ var mixinElementImpl = mixinElement as ClassElementImpl;
if (mixinElementImpl.superInvokedNames.isEmpty) {
return false;
}
@@ -4903,7 +4909,7 @@
if (withClause == null) {
return;
}
- ClassElement classElement = node.declaredElement;
+ var classElement = node.declaredElement as ClassElement;
var supertype = classElement.supertype;
var interfacesMerger = InterfacesMerger(_typeSystem);
@@ -5308,7 +5314,7 @@
if (fieldDeclaration is FieldDeclaration) {
for (VariableDeclaration field in fieldDeclaration.fields.variables) {
if (field.initializer == null) {
- fields.add(field.declaredElement);
+ fields.add(field.declaredElement as FieldElement);
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
index a3a03ad..c43c75f 100644
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ b/pkg/analyzer/lib/src/generated/parser_fasta.dart
@@ -72,7 +72,7 @@
currentToken = fastaParser
.parseMetadata(fastaParser.syntheticPreviousToken(currentToken))
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as Annotation;
}
@override
@@ -82,7 +82,7 @@
currentToken = fastaParser
.parseArguments(fastaParser.syntheticPreviousToken(currentToken))
.next;
- MethodInvocation invocation = astBuilder.pop();
+ var invocation = astBuilder.pop() as MethodInvocation;
return invocation.argumentList.arguments[0];
}
@@ -92,7 +92,9 @@
.parseArguments(fastaParser.syntheticPreviousToken(currentToken))
.next;
var result = astBuilder.pop();
- return result is MethodInvocation ? result.argumentList : result;
+ return result is MethodInvocation
+ ? result.argumentList
+ : result as ArgumentList;
}
@override
@@ -124,7 +126,7 @@
null /* leftBracket */,
<ClassMember>[],
null /* rightBracket */,
- );
+ ) as ClassDeclarationImpl;
// TODO(danrubel): disambiguate between class and mixin
currentToken = fastaParser.parseClassMember(currentToken, className);
//currentToken = fastaParser.parseMixinMember(currentToken);
@@ -138,7 +140,7 @@
currentToken = fastaParser
.parseCombinatorStar(fastaParser.syntheticPreviousToken(currentToken))
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as List<Combinator>;
}
@override
@@ -150,7 +152,7 @@
@override
CompilationUnit parseCompilationUnit2() {
currentToken = fastaParser.parseUnit(currentToken);
- return astBuilder.pop();
+ return astBuilder.pop() as CompilationUnit;
}
@override
@@ -161,7 +163,7 @@
currentToken = fastaParser
.parseConditionalUri(fastaParser.syntheticPreviousToken(currentToken))
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as Configuration;
}
@override
@@ -176,7 +178,7 @@
@override
CompilationUnit parseDirectives2() {
currentToken = fastaParser.parseDirectives(currentToken);
- return astBuilder.pop();
+ return astBuilder.pop() as CompilationUnit;
}
@override
@@ -184,7 +186,7 @@
currentToken = fastaParser
.parseDottedName(fastaParser.syntheticPreviousToken(currentToken))
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as DottedName;
}
@override
@@ -201,7 +203,7 @@
currentToken = fastaParser
.parseExpression(fastaParser.syntheticPreviousToken(currentToken))
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as Expression;
}
@override
@@ -216,7 +218,7 @@
? fasta.MemberKind.GeneralizedFunctionType
: fasta.MemberKind.NonStaticMethod)
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as FormalParameterList;
}
@override
@@ -226,11 +228,12 @@
fastaParser.syntheticPreviousToken(currentToken));
currentToken =
fastaParser.parseFunctionBody(currentToken, inExpression, mayBeEmpty);
- return astBuilder.pop();
+ return astBuilder.pop() as FunctionBody;
}
@override
- FunctionExpression parseFunctionExpression() => parseExpression2();
+ FunctionExpression parseFunctionExpression() =>
+ parseExpression2() as FunctionExpression;
@override
Expression parseLogicalAndExpression() => parseExpression2();
@@ -242,13 +245,14 @@
Expression parseMultiplicativeExpression() => parseExpression2();
@override
- InstanceCreationExpression parseNewExpression() => parseExpression2();
+ InstanceCreationExpression parseNewExpression() =>
+ parseExpression2() as InstanceCreationExpression;
@override
Expression parsePostfixExpression() => parseExpression2();
@override
- Identifier parsePrefixedIdentifier() => parseExpression2();
+ Identifier parsePrefixedIdentifier() => parseExpression2() as Identifier;
@override
Expression parsePrimaryExpression() {
@@ -256,7 +260,7 @@
.parsePrimary(fastaParser.syntheticPreviousToken(currentToken),
fasta.IdentifierContext.expression)
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as Expression;
}
@override
@@ -271,7 +275,7 @@
@override
SimpleIdentifier parseSimpleIdentifier(
{bool allowKeyword = false, bool isDeclaration = false}) =>
- parseExpression2();
+ parseExpression2() as SimpleIdentifier;
@override
Statement parseStatement(Token token) {
@@ -284,14 +288,14 @@
currentToken = fastaParser
.parseStatement(fastaParser.syntheticPreviousToken(currentToken))
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as Statement;
}
@override
- StringLiteral parseStringLiteral() => parseExpression2();
+ StringLiteral parseStringLiteral() => parseExpression2() as StringLiteral;
@override
- SymbolLiteral parseSymbolLiteral() => parseExpression2();
+ SymbolLiteral parseSymbolLiteral() => parseExpression2() as SymbolLiteral;
@override
Expression parseThrowExpression() => parseExpression2();
@@ -312,7 +316,7 @@
.computeType(previous, true, !inExpression)
.parseType(previous, fastaParser)
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as TypeAnnotation;
}
@override
@@ -322,7 +326,7 @@
.computeTypeParamOrArg(previous)
.parseArguments(previous, fastaParser)
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as TypeArgumentList;
}
@override
@@ -332,7 +336,7 @@
.computeType(previous, true, !inExpression)
.parseType(previous, fastaParser)
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as TypeName;
}
@override
@@ -352,7 +356,7 @@
.computeTypeParamOrArg(token, true)
.parseVariables(token, fastaParser)
.next;
- return astBuilder.pop();
+ return astBuilder.pop() as TypeParameterList;
}
@override
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 4cbf579..56ed8d4 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -275,7 +275,7 @@
inheritanceManager,
definingLibrary,
source,
- definingLibrary.typeSystem,
+ definingLibrary.typeSystem as TypeSystemImpl,
typeProvider,
errorListener,
featureSet ??
@@ -301,7 +301,8 @@
MigrationResolutionHooks migrationResolutionHooks)
: _featureSet = featureSet,
migrationResolutionHooks = migrationResolutionHooks,
- super(definingLibrary, source, typeProvider, errorListener,
+ super(definingLibrary, source, typeProvider as TypeProviderImpl,
+ errorListener,
nameScope: nameScope) {
_promoteManager = TypePromotionManager(typeSystem);
@@ -463,7 +464,8 @@
}
if (element is VariableElement) {
- var assigned = _flowAnalysis.isDefinitelyAssigned(node, element);
+ var assigned = _flowAnalysis.isDefinitelyAssigned(
+ node, element as PromotableElement);
var unassigned = _flowAnalysis.isDefinitelyUnassigned(node, element);
if (element.isLate) {
@@ -546,7 +548,7 @@
_flowAnalysis.flow.nullAwareAccess_end();
} while (identical(_unfinishedNullShorts.last, node));
if (node is! CascadeExpression && !discardType) {
- node.staticType = typeSystem.makeNullable(node.staticType);
+ node.staticType = typeSystem.makeNullable(node.staticType as TypeImpl);
}
}
}
@@ -670,7 +672,7 @@
if (element is PropertyAccessorElement && element.isGetter) {
readType = element.returnType;
} else if (element is VariableElement) {
- readType = localVariableTypeProvider.getType(node);
+ readType = localVariableTypeProvider.getType(node as SimpleIdentifier);
}
}
@@ -764,7 +766,7 @@
/// Otherwise, return the original element.
T toLegacyElement<T extends Element>(T element) {
if (_isNonNullableByDefault) return element;
- return Member.legacy(element);
+ return Member.legacy(element) as T;
}
/// If in a legacy library, return the legacy version of the [type].
@@ -877,7 +879,7 @@
@override
void visitAssignmentExpression(AssignmentExpression node) {
- _assignmentExpressionResolver.resolve(node);
+ _assignmentExpressionResolver.resolve(node as AssignmentExpressionImpl);
}
@override
@@ -892,7 +894,7 @@
@override
void visitBinaryExpression(BinaryExpression node) {
- _binaryExpressionResolver.resolve(node);
+ _binaryExpressionResolver.resolve(node as BinaryExpressionImpl);
}
@override
@@ -1127,7 +1129,7 @@
_promoteManager.exitFunctionBody();
}
- ConstructorElementImpl constructor = node.declaredElement;
+ var constructor = node.declaredElement as ConstructorElementImpl;
constructor.constantInitializers =
_createCloner().cloneNodeList(node.initializers);
@@ -1315,12 +1317,12 @@
@override
void visitForElementInScope(ForElement node) {
- _forResolver.resolveElement(node);
+ _forResolver.resolveElement(node as ForElementImpl);
}
@override
void visitForStatementInScope(ForStatement node) {
- _forResolver.resolveStatement(node);
+ _forResolver.resolveStatement(node as ForStatementImpl);
nullSafetyDeadCodeVerifier?.flowEnd(node.body);
}
@@ -1415,7 +1417,8 @@
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function?.accept(this);
- _functionExpressionInvocationResolver.resolve(node);
+ _functionExpressionInvocationResolver
+ .resolve(node as FunctionExpressionInvocationImpl);
}
@override
@@ -1540,7 +1543,7 @@
);
var element = result.readElement;
- node.staticElement = element;
+ node.staticElement = element as MethodElement;
InferenceContext.setType(node.index, result.indexContextType);
node.index?.accept(this);
@@ -1708,7 +1711,7 @@
@override
void visitPostfixExpression(PostfixExpression node) {
- _postfixExpressionResolver.resolve(node);
+ _postfixExpressionResolver.resolve(node as PostfixExpressionImpl);
}
@override
@@ -1718,7 +1721,7 @@
@override
void visitPrefixExpression(PrefixExpression node) {
- _prefixExpressionResolver.resolve(node);
+ _prefixExpressionResolver.resolve(node as PrefixExpressionImpl);
}
@override
@@ -1927,8 +1930,8 @@
var catchClause = catchClauses[i];
nullSafetyDeadCodeVerifier.verifyCatchClause(catchClause);
flow.tryCatchStatement_catchBegin(
- catchClause.exceptionParameter?.staticElement,
- catchClause.stackTraceParameter?.staticElement,
+ catchClause.exceptionParameter?.staticElement as PromotableElement,
+ catchClause.stackTraceParameter?.staticElement as PromotableElement,
);
catchClause.accept(this);
flow.tryCatchStatement_catchEnd();
@@ -1952,7 +1955,7 @@
@override
void visitVariableDeclaration(VariableDeclaration node) {
- _variableDeclarationResolver.resolve(node);
+ _variableDeclarationResolver.resolve(node as VariableDeclarationImpl);
var declaredElement = node.declaredElement;
if (node.parent.parent is ForParts) {
@@ -1966,10 +1969,12 @@
var initializerStaticType = initializer.staticType;
if (declaredType == null) {
if (initializerStaticType is TypeParameterType) {
- _flowAnalysis?.flow?.promote(declaredElement, initializerStaticType);
+ _flowAnalysis?.flow?.promote(
+ declaredElement as PromotableElement, initializerStaticType);
}
} else if (!parent.isFinal) {
- _flowAnalysis?.flow?.write(declaredElement, initializerStaticType,
+ _flowAnalysis?.flow?.write(
+ declaredElement as PromotableElement, initializerStaticType,
viaInitializer: true);
}
}
@@ -2102,7 +2107,7 @@
// as computing constant values. It is stored in two places.
var constructorElement = ConstructorMember.from(
rawElement,
- inferred.returnType,
+ inferred.returnType as InterfaceType,
);
constructorElement = toLegacyElement(constructorElement);
constructor.staticElement = constructorElement;
@@ -2111,7 +2116,7 @@
if (inferred == null) {
var type = originalElement?.type;
- type = toLegacyTypeIfOptOut(type);
+ type = toLegacyTypeIfOptOut(type) as FunctionType;
InferenceContext.setType(node.argumentList, type);
}
}
@@ -2141,7 +2146,8 @@
}
}
- _functionExpressionInvocationResolver.resolve(node);
+ _functionExpressionInvocationResolver
+ .resolve(node as FunctionExpressionInvocationImpl);
nullShortingTermination(node);
}
@@ -2804,7 +2810,7 @@
void visitGenericTypeAlias(GenericTypeAlias node) {
Scope outerScope = nameScope;
try {
- FunctionTypeAliasElement element = node.declaredElement;
+ var element = node.declaredElement as FunctionTypeAliasElement;
nameScope = TypeParameterScope(nameScope, element.typeParameters);
super.visitGenericTypeAlias(node);
@@ -3053,7 +3059,8 @@
VariableResolverVisitor(LibraryElement definingLibrary, Source source,
TypeProvider typeProvider, AnalysisErrorListener errorListener,
{Scope nameScope})
- : super(definingLibrary, source, typeProvider, errorListener,
+ : super(definingLibrary, source, typeProvider as TypeProviderImpl,
+ errorListener,
nameScope: nameScope);
@override
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 6a45033..a51dcbc 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -411,7 +411,7 @@
isConst: node.isConst);
if (inferred != null && inferred != originalElement.type) {
- inferred = _resolver.toLegacyTypeIfOptOut(inferred);
+ inferred = _resolver.toLegacyTypeIfOptOut(inferred) as FunctionType;
// Fix up the parameter elements based on inferred method.
arguments.correspondingStaticParameters =
ResolverVisitor.resolveArgumentsToParameters(
@@ -421,7 +421,7 @@
// computing constant values. It is stored in two places.
var constructorElement = ConstructorMember.from(
rawElement,
- inferred.returnType,
+ inferred.returnType as InterfaceType,
);
constructorElement = _resolver.toLegacyElement(constructorElement);
constructor.staticElement = constructorElement;
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index c0c1b6e..786a77f 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -162,10 +162,10 @@
// Build the enum.
//
EnumElementImpl enumElement = EnumElementImpl(enumName, -1);
- InterfaceTypeImpl enumType = enumElement.instantiate(
+ var enumType = enumElement.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.star,
- );
+ ) as InterfaceTypeImpl;
//
// Populate the fields.
//
@@ -462,11 +462,12 @@
if (isConst) {
ConstTopLevelVariableElementImpl constant =
ConstTopLevelVariableElementImpl(name, -1);
+ var typeElement = type.element as ClassElement;
InstanceCreationExpression initializer =
AstTestFactory.instanceCreationExpression2(
- Keyword.CONST, AstTestFactory.typeName(type.element));
+ Keyword.CONST, AstTestFactory.typeName(typeElement));
if (type is InterfaceType) {
- ConstructorElement element = type.element.unnamedConstructor;
+ ConstructorElement element = typeElement.unnamedConstructor;
initializer.constructorName.staticElement = element;
}
constant.constantInitializer = initializer;
diff --git a/pkg/analyzer/lib/src/generated/type_promotion_manager.dart b/pkg/analyzer/lib/src/generated/type_promotion_manager.dart
index 1858a9b..3ac9ea4 100644
--- a/pkg/analyzer/lib/src/generated/type_promotion_manager.dart
+++ b/pkg/analyzer/lib/src/generated/type_promotion_manager.dart
@@ -132,7 +132,8 @@
void _clearTypePromotionsIfAccessedInClosureAndPotentiallyMutated(
AstNode target) {
for (Element element in _promotedElements) {
- if (_currentFunctionBody.isPotentiallyMutatedInScope(element)) {
+ if (_currentFunctionBody
+ .isPotentiallyMutatedInScope(element as VariableElement)) {
if (_isVariableAccessedInClosure(element, target)) {
_setType(element, null);
}
diff --git a/pkg/analyzer/lib/src/generated/utilities_general.dart b/pkg/analyzer/lib/src/generated/utilities_general.dart
index cbbbaa9..025dc92 100644
--- a/pkg/analyzer/lib/src/generated/utilities_general.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_general.dart
@@ -83,14 +83,14 @@
}
/// Combines together two hash codes.
- static int hash2(Object a, Object b) => finish(combine(combine(0, a), b));
+ static int hash2(int a, int b) => finish(combine(combine(0, a), b));
/// Combines together three hash codes.
- static int hash3(Object a, Object b, Object c) =>
+ static int hash3(int a, int b, int c) =>
finish(combine(combine(combine(0, a), b), c));
/// Combines together four hash codes.
- static int hash4(Object a, Object b, Object c, Object d) =>
+ static int hash4(int a, int b, int c, int d) =>
finish(combine(combine(combine(combine(0, a), b), c), d));
}
diff --git a/pkg/analyzer/lib/src/lint/config.dart b/pkg/analyzer/lib/src/lint/config.dart
index f18198a..4286bd5 100644
--- a/pkg/analyzer/lib/src/lint/config.dart
+++ b/pkg/analyzer/lib/src/lint/config.dart
@@ -20,7 +20,8 @@
/// Process the given option [fileContents] and produce a corresponding
/// [LintConfig].
LintConfig processAnalysisOptionsFile(String fileContents, {String fileUrl}) {
- var yaml = loadYamlNode(fileContents, sourceUrl: fileUrl);
+ var yaml = loadYamlNode(fileContents,
+ sourceUrl: fileUrl != null ? Uri.parse(fileUrl) : null);
if (yaml is YamlMap) {
return parseConfig(yaml);
}
@@ -101,7 +102,8 @@
}
void _parse(String src, {String sourceUrl}) {
- var yaml = loadYamlNode(src, sourceUrl: sourceUrl);
+ var yaml = loadYamlNode(src,
+ sourceUrl: sourceUrl != null ? Uri.parse(sourceUrl) : null);
if (yaml is YamlMap) {
_parseYaml(yaml);
}
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 90c2bb1..c291ea0 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -114,14 +114,15 @@
if (body is ExpressionFunctionBody) {
returnExp = body.expression;
} else {
- ReturnStatement stmt = (body as BlockFunctionBody).block.statements[0];
+ var stmt =
+ (body as BlockFunctionBody).block.statements[0] as ReturnStatement;
returnExp = stmt.expression;
}
DartType type = returnExp.staticType;
if (returnExp is AwaitExpression) {
type = returnExp.expression.staticType;
}
- typeTest(type);
+ typeTest(type as InterfaceType);
}
check("f0", _isFutureOfDynamic);
@@ -168,14 +169,15 @@
if (body is ExpressionFunctionBody) {
returnExp = body.expression;
} else {
- ReturnStatement stmt = (body as BlockFunctionBody).block.statements[0];
+ var stmt =
+ (body as BlockFunctionBody).block.statements[0] as ReturnStatement;
returnExp = stmt.expression;
}
DartType type = returnExp.staticType;
if (returnExp is AwaitExpression) {
type = returnExp.expression.staticType;
}
- typeTest(type);
+ typeTest(type as InterfaceType);
}
check("f0", _isFutureOfDynamic);
@@ -209,9 +211,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
CascadeExpression fetch(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- CascadeExpression exp = decl.initializer;
+ var exp = decl.initializer as CascadeExpression;
return exp;
}
@@ -219,10 +221,10 @@
CascadeExpression cascade = fetch(0);
_isInstantiationOf(_hasElement(elementA))([_isInt])(cascade.staticType);
- MethodInvocation invoke = cascade.cascadeSections[0];
- FunctionExpression function = invoke.argumentList.arguments[1];
+ var invoke = cascade.cascadeSections[0] as MethodInvocation;
+ var function = invoke.argumentList.arguments[1] as FunctionExpression;
ExecutableElement f0 = function.declaredElement;
- _isListOf(_isInt)(f0.type.returnType);
+ _isListOf(_isInt)(f0.type.returnType as InterfaceType);
expect(f0.type.normalParameterTypes[0], typeProvider.intType);
}
@@ -240,7 +242,7 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test");
- VariableDeclarationStatement stmt = statements[0];
+ var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer;
_isInt(call.staticType);
@@ -260,7 +262,7 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test");
- VariableDeclarationStatement stmt = statements[0];
+ var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer;
_isInt(call.staticType);
@@ -277,7 +279,7 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test");
- VariableDeclarationStatement stmt = statements[0];
+ var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer;
_isInt(call.staticType);
@@ -299,7 +301,7 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test");
- VariableDeclarationStatement stmt = statements[0];
+ var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer;
_isInt(call.staticType);
@@ -323,7 +325,7 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test");
- VariableDeclarationStatement stmt = statements[0];
+ var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer;
_isDynamic(call.staticType);
@@ -339,9 +341,9 @@
await assertNoErrorsInCode(code);
ConstructorDeclaration constructor =
AstFinder.getConstructorInClass(unit, "A", null);
- ConstructorFieldInitializer assignment = constructor.initializers[0];
+ var assignment = constructor.initializers[0] as ConstructorFieldInitializer;
Expression exp = assignment.expression;
- _isListOf(_isString)(exp.staticType);
+ _isListOf(_isString)(exp.staticType as InterfaceType);
}
test_factoryConstructor_propagation() async {
@@ -358,9 +360,9 @@
ConstructorDeclaration constructor =
AstFinder.getConstructorInClass(unit, "A", null);
- BlockFunctionBody body = constructor.body;
- ReturnStatement stmt = body.block.statements[0];
- InstanceCreationExpression exp = stmt.expression;
+ var body = constructor.body as BlockFunctionBody;
+ var stmt = body.block.statements[0] as ReturnStatement;
+ var exp = stmt.expression as InstanceCreationExpression;
ClassElement elementB = AstFinder.getClass(unit, "B").declaredElement;
ClassElement elementA = AstFinder.getClass(unit, "A").declaredElement;
expect(exp.constructorName.type.type.element, elementB);
@@ -380,7 +382,7 @@
VariableDeclaration field = AstFinder.getFieldInClass(unit, "A", "f0");
- _isListOf(_isString)(field.initializer.staticType);
+ _isListOf(_isString)(field.initializer.staticType as InterfaceType);
}
test_functionDeclaration_body_propagation() async {
@@ -403,22 +405,23 @@
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
FunctionDeclaration test1 = AstFinder.getTopLevelFunction(unit, "test1");
- ExpressionFunctionBody body = test1.functionExpression.body;
- assertListOfInt(body.expression.staticType);
+ var body = test1.functionExpression.body as ExpressionFunctionBody;
+ assertListOfInt(body.expression.staticType as InterfaceType);
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test2");
FunctionDeclaration inner =
(statements[0] as FunctionDeclarationStatement).functionDeclaration;
- BlockFunctionBody body0 = inner.functionExpression.body;
- ReturnStatement return0 = body0.block.statements[0];
+ var body0 = inner.functionExpression.body as BlockFunctionBody;
+ var return0 = body0.block.statements[0] as ReturnStatement;
Expression anon0 = return0.expression;
- FunctionType type0 = anon0.staticType;
+ var type0 = anon0.staticType as FunctionType;
expect(type0.returnType, typeProvider.intType);
expect(type0.normalParameterTypes[0], typeProvider.stringType);
- FunctionExpression anon1 = (statements[1] as ReturnStatement).expression;
+ var anon1 =
+ (statements[1] as ReturnStatement).expression as FunctionExpression;
FunctionType type1 = anon1.declaredElement.type;
expect(type1.returnType, typeProvider.intType);
expect(type1.normalParameterTypes[0], typeProvider.intType);
@@ -450,9 +453,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- FunctionExpression exp = decl.initializer;
+ var exp = decl.initializer as FunctionExpression;
return exp.declaredElement.type;
}
@@ -488,9 +491,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- FunctionExpression exp = decl.initializer;
+ var exp = decl.initializer as FunctionExpression;
return exp.declaredElement.type;
}
@@ -525,9 +528,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
Expression functionReturnValue(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- FunctionExpression exp = decl.initializer;
+ var exp = decl.initializer as FunctionExpression;
FunctionBody body = exp.body;
if (body is ExpressionFunctionBody) {
return body.expression;
@@ -538,10 +541,10 @@
}
Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
- assertListOfString(functionReturnValue(0).staticType);
- assertListOfString(functionReturnValue(1).staticType);
- assertListOfString(functionReturnValue(2).staticType);
- assertListOfString(functionReturnValue(3).staticType);
+ assertListOfString(functionReturnValue(0).staticType as InterfaceType);
+ assertListOfString(functionReturnValue(1).staticType as InterfaceType);
+ assertListOfString(functionReturnValue(2).staticType as InterfaceType);
+ assertListOfString(functionReturnValue(3).staticType as InterfaceType);
}
test_functionLiteral_functionExpressionInvocation_typedArguments() async {
@@ -567,9 +570,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- ExpressionStatement stmt = statements[i];
- FunctionExpressionInvocation invk = stmt.expression;
- FunctionExpression exp = invk.argumentList.arguments[0];
+ var stmt = statements[i] as ExpressionStatement;
+ var invk = stmt.expression as FunctionExpressionInvocation;
+ var exp = invk.argumentList.arguments[0] as FunctionExpression;
return exp.declaredElement.type;
}
@@ -602,9 +605,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- ExpressionStatement stmt = statements[i];
- FunctionExpressionInvocation invk = stmt.expression;
- FunctionExpression exp = invk.argumentList.arguments[0];
+ var stmt = statements[i] as ExpressionStatement;
+ var invk = stmt.expression as FunctionExpressionInvocation;
+ var exp = invk.argumentList.arguments[0] as FunctionExpression;
return exp.declaredElement.type;
}
@@ -636,9 +639,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- ExpressionStatement stmt = statements[i];
- MethodInvocation invk = stmt.expression;
- FunctionExpression exp = invk.argumentList.arguments[0];
+ var stmt = statements[i] as ExpressionStatement;
+ var invk = stmt.expression as MethodInvocation;
+ var exp = invk.argumentList.arguments[0] as FunctionExpression;
return exp.declaredElement.type;
}
@@ -669,9 +672,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- ExpressionStatement stmt = statements[i];
- MethodInvocation invk = stmt.expression;
- FunctionExpression exp = invk.argumentList.arguments[0];
+ var stmt = statements[i] as ExpressionStatement;
+ var invk = stmt.expression as MethodInvocation;
+ var exp = invk.argumentList.arguments[0] as FunctionExpression;
return exp.declaredElement.type;
}
@@ -705,9 +708,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- ExpressionStatement stmt = statements[i];
- MethodInvocation invk = stmt.expression;
- FunctionExpression exp = invk.argumentList.arguments[0];
+ var stmt = statements[i] as ExpressionStatement;
+ var invk = stmt.expression as MethodInvocation;
+ var exp = invk.argumentList.arguments[0] as FunctionExpression;
return exp.declaredElement.type;
}
@@ -740,9 +743,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- ExpressionStatement stmt = statements[i];
- MethodInvocation invk = stmt.expression;
- FunctionExpression exp = invk.argumentList.arguments[0];
+ var stmt = statements[i] as ExpressionStatement;
+ var invk = stmt.expression as MethodInvocation;
+ var exp = invk.argumentList.arguments[0] as FunctionExpression;
return exp.declaredElement.type;
}
@@ -778,9 +781,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
Expression functionReturnValue(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- FunctionExpression exp = decl.initializer;
+ var exp = decl.initializer as FunctionExpression;
FunctionBody body = exp.body;
if (body is ExpressionFunctionBody) {
return body.expression;
@@ -803,7 +806,7 @@
FutureOr<T> mk<T>(Future<T> x) => x;
test() => mk(new Future<int>.value(42));
''');
- _isFutureOrOfInt(invoke.staticType);
+ _isFutureOrOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_assignFromValue() async {
@@ -812,7 +815,7 @@
FutureOr<T> mk<T>(T x) => x;
test() => mk(42);
''');
- _isFutureOrOfInt(invoke.staticType);
+ _isFutureOrOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_asyncExpressionBody() async {
@@ -821,7 +824,7 @@
Future<T> mk<T>(FutureOr<T> x) async => x;
test() => mk(42);
''');
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_asyncReturn() async {
@@ -830,7 +833,7 @@
Future<T> mk<T>(FutureOr<T> x) async { return x; }
test() => mk(42);
''');
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_await() async {
@@ -839,7 +842,7 @@
Future<T> mk<T>(FutureOr<T> x) async => await x;
test() => mk(42);
''');
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards1() async {
@@ -849,7 +852,7 @@
Future<T> mk<T>(FutureOr<T> x) => null;
Future<int> test() => mk(new Future<int>.value(42));
''');
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards2() async {
@@ -859,7 +862,7 @@
Future<T> mk<T>(FutureOr<T> x) => null;
FutureOr<int> test() => mk(new Future<int>.value(42));
''');
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards3() async {
@@ -869,8 +872,9 @@
Future<T> mk<T>(FutureOr<T> x) => null;
Future<int> test() => mk(new Future.value(42));
''');
- _isFutureOfInt(invoke.staticType);
- _isFutureOfInt(invoke.argumentList.arguments[0].staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
+ _isFutureOfInt(
+ invoke.argumentList.arguments[0].staticType as InterfaceType);
}
test_futureOr_downwards4() async {
@@ -880,8 +884,9 @@
Future<T> mk<T>(FutureOr<T> x) => null;
FutureOr<int> test() => mk(new Future.value(42));
''');
- _isFutureOfInt(invoke.staticType);
- _isFutureOfInt(invoke.argumentList.arguments[0].staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
+ _isFutureOfInt(
+ invoke.argumentList.arguments[0].staticType as InterfaceType);
}
test_futureOr_downwards5() async {
@@ -891,8 +896,9 @@
Future<T> mk<T>(FutureOr<T> x) => null;
FutureOr<num> test() => mk(new Future.value(42));
''');
- _isFutureOf([_isNum])(invoke.staticType);
- _isFutureOf([_isNum])(invoke.argumentList.arguments[0].staticType);
+ _isFutureOf([_isNum])(invoke.staticType as InterfaceType);
+ _isFutureOf([_isNum])(
+ invoke.argumentList.arguments[0].staticType as InterfaceType);
}
test_futureOr_downwards6() async {
@@ -902,8 +908,9 @@
T mk<T>(T x) => null;
FutureOr<int> test() => mk(new Future.value(42));
''');
- _isFutureOrOfInt(invoke.staticType);
- _isFutureOfInt(invoke.argumentList.arguments[0].staticType);
+ _isFutureOrOfInt(invoke.staticType as InterfaceType);
+ _isFutureOfInt(
+ invoke.argumentList.arguments[0].staticType as InterfaceType);
}
test_futureOr_downwards7() async {
@@ -913,8 +920,9 @@
T mk<T extends Future<int>>(T x) => null;
FutureOr<int> test() => mk(new Future.value(42));
''');
- _isFutureOfInt(invoke.staticType);
- _isFutureOfInt(invoke.argumentList.arguments[0].staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
+ _isFutureOfInt(
+ invoke.argumentList.arguments[0].staticType as InterfaceType);
}
test_futureOr_downwards8() async {
@@ -926,8 +934,9 @@
T mk<T extends Future<Object>>(T x) => null;
FutureOr<int> test() => mk(new Future.value(42));
''');
- _isFutureOfInt(invoke.staticType);
- _isFutureOfInt(invoke.argumentList.arguments[0].staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
+ _isFutureOfInt(
+ invoke.argumentList.arguments[0].staticType as InterfaceType);
}
test_futureOr_downwards9() async {
@@ -937,7 +946,7 @@
List<T> mk<T>(T x) => null;
FutureOr<List<int>> test() => mk(3);
''');
- _isListOf(_isInt)(invoke.staticType);
+ _isListOf(_isInt)(invoke.staticType as InterfaceType);
_isInt(invoke.argumentList.arguments[0].staticType);
}
@@ -987,7 +996,7 @@
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].staticType);
- _isFutureOfNull(invoke.staticType);
+ _isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOr_no_return_value() async {
@@ -998,7 +1007,7 @@
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].staticType);
- _isFutureOfNull(invoke.staticType);
+ _isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOr_return_null() async {
@@ -1009,7 +1018,7 @@
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].staticType);
- _isFutureOfNull(invoke.staticType);
+ _isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOr_upwards1() async {
@@ -1019,7 +1028,7 @@
Future<T> mk<T>(FutureOr<T> x) => null;
dynamic test() => mk(new Future<int>.value(42));
''');
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_upwards2() async {
@@ -1031,7 +1040,7 @@
''', expectedErrors: [
error(CompileTimeErrorCode.COULD_NOT_INFER, 111, 2),
]);
- _isFutureOfInt(invoke.staticType);
+ _isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOrNull_no_return() async {
@@ -1042,7 +1051,7 @@
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].staticType);
- _isFutureOfNull(invoke.staticType);
+ _isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOrNull_no_return_value() async {
@@ -1053,7 +1062,7 @@
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].staticType);
- _isFutureOfNull(invoke.staticType);
+ _isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOrNull_return_null() async {
@@ -1064,7 +1073,7 @@
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].staticType);
- _isFutureOfNull(invoke.staticType);
+ _isFutureOfNull(invoke.staticType as InterfaceType);
}
test_generic_partial() async {
@@ -1106,7 +1115,7 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test");
void check(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression init = decl.initializer;
_isInstantiationOf(_hasElement(elementA))([_isInt])(init.staticType);
@@ -1332,9 +1341,9 @@
var body = AstFinder.getTopLevelFunction(unit, '_mergeSort')
.functionExpression
.body as BlockFunctionBody;
- var stmts = body.block.statements;
+ var stmts = body.block.statements.cast<ExpressionStatement>();
for (ExpressionStatement stmt in stmts) {
- MethodInvocation invoke = stmt.expression;
+ var invoke = stmt.expression as MethodInvocation;
assertInvokeType(invoke,
'void Function(T Function(T), int Function(T, T), T Function(T))');
}
@@ -1359,9 +1368,9 @@
var body = AstFinder.getTopLevelFunction(unit, '_mergeSort')
.functionExpression
.body as BlockFunctionBody;
- var stmts = body.block.statements;
+ var stmts = body.block.statements.cast<ExpressionStatement>();
for (ExpressionStatement stmt in stmts) {
- MethodInvocation invoke = stmt.expression;
+ var invoke = stmt.expression as MethodInvocation;
assertInvokeType(
invoke, 'void Function(List<T>, int Function(T, T), List<T>)');
}
@@ -1386,9 +1395,9 @@
var body = AstFinder.getTopLevelFunction(unit, '_mergeSort')
.functionExpression
.body as BlockFunctionBody;
- var stmts = body.block.statements;
+ var stmts = body.block.statements.cast<ExpressionStatement>();
for (ExpressionStatement stmt in stmts) {
- MethodInvocation invoke = stmt.expression;
+ var invoke = stmt.expression as MethodInvocation;
assertInvokeType(invoke, 'void Function(T, int Function(T, T), T)');
}
}
@@ -1459,26 +1468,26 @@
await assertNoErrorsInCode(code);
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
- Asserter<InterfaceType> assertMapOfIntToListOfInt =
- _isMapOf(_isInt, (DartType type) => assertListOfInt(type));
+ Asserter<InterfaceType> assertMapOfIntToListOfInt = _isMapOf(
+ _isInt, (DartType type) => assertListOfInt(type as InterfaceType));
VariableDeclaration mapB = AstFinder.getFieldInClass(unit, "B", "map");
MethodDeclaration mapC = AstFinder.getMethodInClass(unit, "C", "map");
- assertMapOfIntToListOfInt(mapB.declaredElement.type);
- assertMapOfIntToListOfInt(mapC.declaredElement.returnType);
+ assertMapOfIntToListOfInt(mapB.declaredElement.type as InterfaceType);
+ assertMapOfIntToListOfInt(mapC.declaredElement.returnType as InterfaceType);
- SetOrMapLiteral mapLiteralB = mapB.initializer;
- SetOrMapLiteral mapLiteralC =
- (mapC.body as ExpressionFunctionBody).expression;
- assertMapOfIntToListOfInt(mapLiteralB.staticType);
- assertMapOfIntToListOfInt(mapLiteralC.staticType);
+ var mapLiteralB = mapB.initializer as SetOrMapLiteral;
+ var mapLiteralC =
+ (mapC.body as ExpressionFunctionBody).expression as SetOrMapLiteral;
+ assertMapOfIntToListOfInt(mapLiteralB.staticType as InterfaceType);
+ assertMapOfIntToListOfInt(mapLiteralC.staticType as InterfaceType);
- ListLiteral listLiteralB =
- (mapLiteralB.elements[0] as MapLiteralEntry).value;
- ListLiteral listLiteralC =
- (mapLiteralC.elements[0] as MapLiteralEntry).value;
- assertListOfInt(listLiteralB.staticType);
- assertListOfInt(listLiteralC.staticType);
+ var listLiteralB =
+ (mapLiteralB.elements[0] as MapLiteralEntry).value as ListLiteral;
+ var listLiteralC =
+ (mapLiteralC.elements[0] as MapLiteralEntry).value as ListLiteral;
+ assertListOfInt(listLiteralB.staticType as InterfaceType);
+ assertListOfInt(listLiteralC.staticType as InterfaceType);
}
test_instanceCreation() async {
@@ -1671,7 +1680,8 @@
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test0");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test0")
+ .cast<VariableDeclarationStatement>();
hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
@@ -1684,14 +1694,15 @@
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test1");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test1")
+ .cast<VariableDeclarationStatement>();
hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
}
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test2").cast<VariableDeclarationStatement>();
hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[2]));
@@ -1702,14 +1713,14 @@
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test3");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test3").cast<VariableDeclarationStatement>();
hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
}
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test4");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test4").cast<VariableDeclarationStatement>();
hasType(assertCOf([_isInt]), rhs(statements[0]));
hasType(assertCOf([_isInt]), rhs(statements[1]));
hasType(assertCOf([_isInt]), rhs(statements[2]));
@@ -1720,7 +1731,7 @@
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test5");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test5").cast<VariableDeclarationStatement>();
hasType(assertCOf([_isInt]), rhs(statements[0]));
hasType(assertCOf([_isInt]), rhs(statements[1]));
}
@@ -1730,7 +1741,7 @@
// context. We could choose a tighter type, but currently
// we just use dynamic.
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test6");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test6").cast<VariableDeclarationStatement>();
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
hasType(assertDOf([_isInt, _isString]), rhs(statements[2]));
@@ -1741,20 +1752,20 @@
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test7");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test7").cast<VariableDeclarationStatement>();
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
}
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test8");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test8").cast<VariableDeclarationStatement>();
hasType(assertEOf([_isInt, _isString]), rhs(statements[0]));
}
{
List<Statement> statements =
- AstFinder.getStatementsInTopLevelFunction(unit, "test9");
+ AstFinder.getStatementsInTopLevelFunction(unit, "test9").cast<VariableDeclarationStatement>();
hasType(assertFOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[1]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[2]));
@@ -1784,9 +1795,9 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
ListLiteral literal(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- ListLiteral exp = decl.initializer;
+ var exp = decl.initializer as ListLiteral;
return exp;
}
@@ -1794,14 +1805,14 @@
Asserter<InterfaceType> assertListOfListOfInt =
_isListOf((DartType type) => assertListOfInt(type));
- assertListOfListOfInt(literal(0).staticType);
- assertListOfListOfInt(literal(1).staticType);
- assertListOfListOfInt(literal(2).staticType);
- assertListOfListOfInt(literal(3).staticType);
+ assertListOfListOfInt(literal(0).staticType as InterfaceType);
+ assertListOfListOfInt(literal(1).staticType as InterfaceType);
+ assertListOfListOfInt(literal(2).staticType as InterfaceType);
+ assertListOfListOfInt(literal(3).staticType as InterfaceType);
- assertListOfInt((literal(1).elements[0] as Expression).staticType);
- assertListOfInt((literal(2).elements[0] as Expression).staticType);
- assertListOfInt((literal(3).elements[0] as Expression).staticType);
+ assertListOfInt((literal(1).elements[0] as Expression).staticType as InterfaceType);
+ assertListOfInt((literal(2).elements[0] as Expression).staticType as InterfaceType);
+ assertListOfInt((literal(3).elements[0] as Expression).staticType as InterfaceType);
}
test_listLiteral_simple() async {
@@ -1825,18 +1836,18 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- ListLiteral exp = decl.initializer;
+ var exp = decl.initializer as ListLiteral;
return exp.staticType;
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
- assertListOfInt(literal(0));
- assertListOfInt(literal(1));
- assertListOfInt(literal(2));
- assertListOfInt(literal(3));
+ assertListOfInt(literal(0) as InterfaceType);
+ assertListOfInt(literal(1) as InterfaceType);
+ assertListOfInt(literal(2) as InterfaceType);
+ assertListOfInt(literal(3) as InterfaceType);
}
test_listLiteral_simple_const() async {
@@ -1860,18 +1871,18 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- ListLiteral exp = decl.initializer;
+ var exp = decl.initializer as ListLiteral;
return exp.staticType;
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
- assertListOfInt(literal(0));
- assertListOfInt(literal(1));
- assertListOfInt(literal(2));
- assertListOfInt(literal(3));
+ assertListOfInt(literal(0) as InterfaceType);
+ assertListOfInt(literal(1) as InterfaceType);
+ assertListOfInt(literal(2) as InterfaceType);
+ assertListOfInt(literal(3) as InterfaceType);
}
test_listLiteral_simple_disabled() async {
@@ -1897,16 +1908,16 @@
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "main");
DartType literal(int i) {
- VariableDeclarationStatement stmt = statements[i];
+ var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
- ListLiteral exp = decl.initializer;
+ var exp = decl.initializer as ListLiteral;
return exp.staticType;
}
- _isListOf(_isNum)(literal(0));
- _isListOf(_isNum)(literal(1));
- _isListOf(_isString)(literal(2));
- _isListOf(_isDynamic)(literal(3));
+ _isListOf(_isNum)(literal(0) as InterfaceType);
+ _isListOf(_isNum)(literal(1) as InterfaceType);
+ _isListOf(_isString)(literal(2) as InterfaceType);
+ _isListOf(_isDynamic)(literal(3) as InterfaceType);
}
test_listLiteral_simple_subtype() async {
diff --git a/pkg/analyzer/test/src/fasta/message_coverage_test.dart b/pkg/analyzer/test/src/fasta/message_coverage_test.dart
index ad28b0e..8b309c8 100644
--- a/pkg/analyzer/test/src/fasta/message_coverage_test.dart
+++ b/pkg/analyzer/test/src/fasta/message_coverage_test.dart
@@ -4,6 +4,7 @@
import 'dart:io' as io;
+import 'package:analysis_tool/package_root.dart' as package_root;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:path/path.dart' as path;
@@ -12,7 +13,6 @@
import 'package:yaml/yaml.dart';
import '../../generated/parser_fasta_test.dart';
-import '../../utils/package_root.dart' as package_root;
main() {
defineReflectiveSuite(() {
diff --git a/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart b/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
index 6d415cf..867debe 100644
--- a/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
+++ b/pkg/analyzer/test/src/summary2/ast_text_printer_integration_test.dart
@@ -4,10 +4,10 @@
import 'dart:io';
+import 'package:analysis_tool/package_root.dart' as package_root;
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:test/test.dart';
-import '../../utils/package_root.dart' as package_root;
import '../dart/ast/parse_base.dart';
import 'ast_text_printer_test.dart';
diff --git a/pkg/analyzer/test/utils/package_root.dart b/pkg/analyzer/test/utils/package_root.dart
deleted file mode 100644
index 8055970..0000000
--- a/pkg/analyzer/test/utils/package_root.dart
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2017, 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';
-
-import 'package:path/path.dart' as pathos;
-
-/// Returns a path to the directory containing source code for packages such as
-/// kernel, front_end, and analyzer.
-String get packageRoot {
- // If the package root directory is specified on the command line using
- // -DpkgRoot=..., use it.
- String pkgRootVar = const bool.hasEnvironment('pkgRoot')
- ? const String.fromEnvironment('pkgRoot')
- : null;
- if (pkgRootVar != null) {
- String path = pathos.join(Directory.current.path, pkgRootVar);
- if (!path.endsWith(pathos.separator)) path += pathos.separator;
- return path;
- }
- // Otherwise try to guess based on the script path.
- String scriptPath = pathos.fromUri(Platform.script);
- List<String> parts = pathos.split(scriptPath);
- int pkgIndex = parts.indexOf('pkg');
- if (pkgIndex != -1) {
- return pathos.joinAll(parts.sublist(0, pkgIndex + 1)) + pathos.separator;
- }
- throw StateError('Unable to find sdk/pkg/ in $scriptPath');
-}
diff --git a/pkg/analyzer/test/verify_docs_test.dart b/pkg/analyzer/test/verify_docs_test.dart
index 5107cd6..2254409 100644
--- a/pkg/analyzer/test/verify_docs_test.dart
+++ b/pkg/analyzer/test/verify_docs_test.dart
@@ -4,6 +4,7 @@
import 'dart:convert';
+import 'package:analysis_tool/package_root.dart' as package_root;
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
@@ -14,8 +15,6 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
-import 'utils/package_root.dart' as package_root;
-
main() async {
SnippetTester tester = SnippetTester();
await tester.verify();
diff --git a/pkg/analyzer/test/verify_tests_test.dart b/pkg/analyzer/test/verify_tests_test.dart
index a25248d..d1e1e17 100644
--- a/pkg/analyzer/test/verify_tests_test.dart
+++ b/pkg/analyzer/test/verify_tests_test.dart
@@ -2,90 +2,28 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/dart/analysis/analysis_context.dart';
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analysis_tool/package_root.dart' as package_root;
+import 'package:analysis_tool/verify_tests.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:path/path.dart' as path;
-import 'package:test/test.dart';
-
-import 'utils/package_root.dart' as package_root;
main() {
- PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
- String packageRoot = provider.pathContext.normalize(package_root.packageRoot);
- String analyzerPath = provider.pathContext.join(packageRoot, 'analyzer');
- String testDirPath = provider.pathContext.join(analyzerPath, 'test');
-
- AnalysisContextCollection collection = AnalysisContextCollection(
- includedPaths: <String>[testDirPath], resourceProvider: provider);
- List<AnalysisContext> contexts = collection.contexts;
- if (contexts.length != 1) {
- fail('The test directory contains multiple analysis contexts.');
- }
-
- buildTestsIn(
- contexts[0].currentSession, testDirPath, provider.getFolder(testDirPath));
+ var provider = PhysicalResourceProvider.INSTANCE;
+ var packageRoot = provider.pathContext.normalize(package_root.packageRoot);
+ var pathToAnalyze = provider.pathContext.join(packageRoot, 'analyzer');
+ var testDirPath = provider.pathContext.join(pathToAnalyze, 'test');
+ _VerifyTests(testDirPath).build();
}
-void buildTestsIn(
- AnalysisSession session, String testDirPath, Folder directory) {
- List<String> testFileNames = [];
- File testAllFile;
- List<Resource> children = directory.getChildren();
- children.sort((first, second) => first.shortName.compareTo(second.shortName));
- for (Resource child in children) {
- if (child is Folder) {
- if (child.getChildAssumingFile('test_all.dart').exists) {
- testFileNames.add('${child.shortName}/test_all.dart');
- }
- buildTestsIn(session, testDirPath, child);
- } else if (child is File) {
- String name = child.shortName;
- if (name == 'test_all.dart') {
- testAllFile = child;
- } else if (name.endsWith('_integration_test.dart')) {
- // ignored
- } else if (name.endsWith('_test.dart')) {
- testFileNames.add(name);
- }
- }
- }
- String relativePath = path.relative(directory.path, from: testDirPath);
- test(relativePath, () {
- if (testFileNames.isEmpty) {
- return;
- }
- if (testAllFile == null) {
- if (relativePath != 'id_tests') {
- fail('Missing "test_all.dart" in $relativePath');
- } else {
- // The tests in the id_tests folder don't have a test_all.dart file
- // because they don't use the package:test framework.
- return;
- }
- }
- ParsedUnitResult result = session.getParsedUnit(testAllFile.path);
- if (result.state != ResultState.VALID) {
- fail('Could not parse ${testAllFile.path}');
- }
- List<String> importedFiles = [];
- for (var directive in result.unit.directives) {
- if (directive is ImportDirective) {
- importedFiles.add(directive.uri.stringValue);
- }
- }
- List<String> missingFiles = [];
- for (String testFileName in testFileNames) {
- if (!importedFiles.contains(testFileName)) {
- missingFiles.add(testFileName);
- }
- }
- if (missingFiles.isNotEmpty) {
- fail('Tests missing from "test_all.dart": ${missingFiles.join(', ')}');
- }
- });
+class _VerifyTests extends VerifyTests {
+ _VerifyTests(String testDirPath, {List<String> excludedPaths})
+ : super(testDirPath, excludedPaths: excludedPaths);
+
+ @override
+ bool isExpensive(Resource resource) =>
+ resource.shortName.endsWith('_integration_test.dart');
+
+ @override
+ bool isOkForTestAllToBeMissing(Folder folder) =>
+ folder.shortName == 'id_tests';
}
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index 5ed14e0..18dcbd2 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -4,6 +4,7 @@
import 'dart:io';
+import 'package:analysis_tool/package_root.dart' as package_root;
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
@@ -12,8 +13,6 @@
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:path/src/context.dart';
-import '../../test/utils/package_root.dart' as package_root;
-
/// Generate the file `diagnostics.md` based on the documentation associated
/// with the declarations of the error codes.
void main() async {
diff --git a/pkg/analyzer/tool/experiments/generate.dart b/pkg/analyzer/tool/experiments/generate.dart
index 6ef4373..ac315ad 100644
--- a/pkg/analyzer/tool/experiments/generate.dart
+++ b/pkg/analyzer/tool/experiments/generate.dart
@@ -4,12 +4,11 @@
import 'package:_fe_analyzer_shared/src/scanner/characters.dart'
show $MINUS, $_;
+import 'package:analysis_tool/package_root.dart' as pkg_root;
import 'package:analysis_tool/tools.dart';
import 'package:path/path.dart';
import 'package:yaml/yaml.dart' show YamlMap, loadYaml;
-import '../../test/utils/package_root.dart' as pkg_root;
-
main() async {
await GeneratedContent.generateAll(
normalize(join(pkg_root.packageRoot, 'analyzer')), allTargets);
diff --git a/pkg/analyzer/tool/messages/generate.dart b/pkg/analyzer/tool/messages/generate.dart
index 31d96ef..23e066e 100644
--- a/pkg/analyzer/tool/messages/generate.dart
+++ b/pkg/analyzer/tool/messages/generate.dart
@@ -13,14 +13,13 @@
import 'dart:io';
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
+import 'package:analysis_tool/package_root.dart' as pkg_root;
import 'package:analysis_tool/tools.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:path/path.dart';
import 'package:yaml/yaml.dart' show loadYaml;
-import '../../test/utils/package_root.dart' as pkg_root;
-
main() async {
String analyzerPkgPath = normalize(join(pkg_root.packageRoot, 'analyzer'));
String frontEndPkgPath = normalize(join(pkg_root.packageRoot, 'front_end'));
diff --git a/pkg/analyzer/tool/summary/check_test.dart b/pkg/analyzer/tool/summary/check_test.dart
index e93bb33..34edda7 100644
--- a/pkg/analyzer/tool/summary/check_test.dart
+++ b/pkg/analyzer/tool/summary/check_test.dart
@@ -2,10 +2,10 @@
// 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:analysis_tool/package_root.dart' as package_root;
import 'package:analysis_tool/tools.dart';
import 'package:path/path.dart';
-import '../../test/utils/package_root.dart' as package_root;
import 'generate.dart';
/// Check that the target file has been code generated. If it hasn't tell the
diff --git a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
index a1d5445..5615b1b 100644
--- a/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
+++ b/pkg/analyzer_plugin/lib/src/protocol/protocol_internal.dart
@@ -8,6 +8,7 @@
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
+import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
final Map<String, RefactoringKind> REQUEST_ID_REFACTORING_KINDS =
HashMap<String, RefactoringKind>();
@@ -18,13 +19,46 @@
edits.forEach(sourceFileEdit.add);
}
-/// Adds the given [sourceEdit] to the list in [sourceFileEdit].
+/// Adds the given [sourceEdit] to the list in [sourceFileEdit] while preserving
+/// two invariants:
+/// - the list is sorted such that edits with a larger offset appear earlier in
+/// the list, and
+/// - no two edits in the list overlap each other.
+///
+/// If the invariants can't be preserved, then a [ConflictingEditException] is
+/// thrown.
void addEditForSource(SourceFileEdit sourceFileEdit, SourceEdit sourceEdit) {
var edits = sourceFileEdit.edits;
+ var length = edits.length;
var index = 0;
- while (index < edits.length && edits[index].offset > sourceEdit.offset) {
+ while (index < length && edits[index].offset > sourceEdit.offset) {
index++;
}
+ if (index > 0) {
+ var previousEdit = edits[index - 1];
+ // The [previousEdit] has an offset that is strictly greater than the offset
+ // of the [sourceEdit] so we only need to look at the end of the
+ // [sourceEdit] to know whether they overlap.
+ if (sourceEdit.offset + sourceEdit.length > previousEdit.offset) {
+ throw ConflictingEditException(
+ newEdit: sourceEdit, existingEdit: previousEdit);
+ }
+ }
+ if (index < length) {
+ var nextEdit = edits[index];
+ // The [nextEdit] has an offset that is less than or equal to the offset of
+ // the [sourceEdit]. If they're equal, then we consider it to be a conflict.
+ // Otherwise the offset of [nextEdit] is strictly less than the offset of
+ // the [sourceEdit] so we need to look at the end of the [nextEdit] to know
+ // whether they overlap.
+ if ((sourceEdit.offset == nextEdit.offset &&
+ sourceEdit.length > 0 &&
+ nextEdit.length > 0) ||
+ nextEdit.offset + nextEdit.length > sourceEdit.offset) {
+ throw ConflictingEditException(
+ newEdit: sourceEdit, existingEdit: nextEdit);
+ }
+ }
edits.insert(index, sourceEdit);
}
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
index ed00442..58d3a20 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
@@ -128,6 +128,43 @@
}
}
+ @override
+ ChangeBuilder copy() {
+ var copy = ChangeBuilderImpl(workspace: workspace, eol: eol);
+ for (var entry in _linkedEditGroups.entries) {
+ copy._linkedEditGroups[entry.key] = _copyLinkedEditGroup(entry.value);
+ }
+ copy._selection = _copyPosition(_selection);
+ copy._selectionRange = _selectionRange;
+ copy._lockedPositions.addAll(_lockedPositions);
+ for (var entry in _genericFileEditBuilders.entries) {
+ copy._genericFileEditBuilders[entry.key] = entry.value.copyWith(copy);
+ }
+ //
+ // The file edit builders for libraries (those whose [libraryChangeBuilder]
+ // is `null`) are copied first so that the copies exist when we copy the
+ // builders for parts and the structure can be preserved.
+ //
+ var editBuilderMap = <DartFileEditBuilderImpl, DartFileEditBuilderImpl>{};
+ for (var entry in _dartFileEditBuilders.entries) {
+ var oldBuilder = entry.value;
+ if (oldBuilder.libraryChangeBuilder == null) {
+ var newBuilder = oldBuilder.copyWith(copy);
+ copy._dartFileEditBuilders[entry.key] = newBuilder;
+ editBuilderMap[oldBuilder] = newBuilder;
+ }
+ }
+ for (var entry in _dartFileEditBuilders.entries) {
+ var oldBuilder = entry.value;
+ if (oldBuilder.libraryChangeBuilder != null) {
+ var newBuilder =
+ oldBuilder.copyWith(copy, editBuilderMap: editBuilderMap);
+ copy._dartFileEditBuilders[entry.key] = newBuilder;
+ }
+ }
+ return copy;
+ }
+
/// Create and return a [DartFileEditBuilder] that can be used to build edits
/// to the Dart file with the given [path].
Future<DartFileEditBuilderImpl> createDartFileEditBuilder(String path) async {
@@ -188,6 +225,17 @@
_selection = position;
}
+ /// Return a copy of the linked edit [group].
+ LinkedEditGroup _copyLinkedEditGroup(LinkedEditGroup group) {
+ return LinkedEditGroup(group.positions.map(_copyPosition).toList(),
+ group.length, group.suggestions.toList());
+ }
+
+ /// Return a copy of the [position].
+ Position _copyPosition(Position position) {
+ return position == null ? null : Position(position.file, position.offset);
+ }
+
void _setSelectionRange(SourceRange range) {
_selectionRange = range;
}
@@ -393,6 +441,13 @@
}
}
+ FileEditBuilderImpl copyWith(ChangeBuilderImpl changeBuilder) {
+ var copy =
+ FileEditBuilderImpl(changeBuilder, fileEdit.file, fileEdit.fileStamp);
+ copy.fileEdit.edits.addAll(fileEdit.edits);
+ return copy;
+ }
+
EditBuilderImpl createEditBuilder(int offset, int length) {
return EditBuilderImpl(this, offset, length);
}
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 4c68006..993cf7e 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
@@ -1312,6 +1312,23 @@
}
@override
+ DartFileEditBuilderImpl copyWith(ChangeBuilderImpl changeBuilder,
+ {Map<DartFileEditBuilderImpl, DartFileEditBuilderImpl> editBuilderMap =
+ const {}}) {
+ var copy = DartFileEditBuilderImpl(changeBuilder, resolvedUnit,
+ fileEdit.fileStamp, editBuilderMap[libraryChangeBuilder]);
+ copy.fileEdit.edits.addAll(fileEdit.edits);
+ copy.importPrefixGenerator = importPrefixGenerator;
+ for (var entry in librariesToImport.entries) {
+ copy.librariesToImport[entry.key] = entry.value;
+ }
+ for (var entry in librariesToRelativelyImport.entries) {
+ copy.librariesToRelativelyImport[entry.key] = entry.value;
+ }
+ return copy;
+ }
+
+ @override
DartEditBuilderImpl createEditBuilder(int offset, int length) {
return DartEditBuilderImpl(this, offset, length);
}
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_core.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_core.dart
index 0d310b5..d4e9f29 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_core.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_core.dart
@@ -56,6 +56,10 @@
Future<void> addGenericFileEdit(
String path, void Function(FileEditBuilder builder) buildFileEdit);
+ /// Return a copy of this change builder that is constructed in such as was
+ /// that changes to the copy will not effect this change builder.
+ ChangeBuilder copy();
+
/// Set the selection for the change being built to the given [position].
void setSelection(Position position);
}
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/conflicting_edit_exception.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/conflicting_edit_exception.dart
new file mode 100644
index 0000000..db5a55f
--- /dev/null
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/conflicting_edit_exception.dart
@@ -0,0 +1,24 @@
+// 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_plugin/protocol/protocol_common.dart';
+import 'package:meta/meta.dart';
+
+/// An exception that is thrown when a change builder is asked to include an
+/// edit that conflicts with a previous edit.
+class ConflictingEditException implements Exception {
+ /// The new edit that was being added.
+ final SourceEdit newEdit;
+
+ /// The existing edit with which it conflicts.
+ final SourceEdit existingEdit;
+
+ /// Initialize a newly created exception indicating that the [newEdit].
+ ConflictingEditException(
+ {@required this.newEdit, @required this.existingEdit});
+
+ @override
+ String toString() =>
+ 'ConflictingEditException: $newEdit conflicts with $existingEdit';
+}
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index f763f70..50a1e05 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -10,13 +10,13 @@
dependencies:
analyzer: '>=0.39.12 <0.41.0'
dart_style: '^1.2.0'
+ meta: ^1.2.3
pub_semver: '^1.3.2'
dev_dependencies:
analysis_tool:
path: ../analysis_tool
html: '>=0.13.1 <0.15.0'
- meta: '^1.1.8'
path: '^1.4.1'
test_reflective_loader: ^0.1.8
test: ^1.0.0
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_core_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_core_test.dart
index 711cf55..0e27f7f 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_core_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_core_test.dart
@@ -6,6 +6,7 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -20,6 +21,75 @@
@reflectiveTest
class ChangeBuilderImplTest {
+ void test_copy_empty() {
+ var builder = ChangeBuilderImpl();
+ var copy = builder.copy() as ChangeBuilderImpl;
+ expect(identical(copy, builder), isFalse);
+ expect(copy.workspace, builder.workspace);
+ expect(copy.eol, builder.eol);
+ }
+
+ Future<void> test_copy_newEdit() async {
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit('/test.dart', (builder) {
+ builder.addSimpleInsertion(0, 'x');
+ });
+ var copy = builder.copy() as ChangeBuilderImpl;
+ await copy.addGenericFileEdit('/test.dart', (builder) {
+ builder.addSimpleInsertion(10, 'x');
+ });
+ var change = builder.sourceChange;
+ expect(change.edits[0].edits, hasLength(1));
+ }
+
+ Future<void> test_copy_newFile() async {
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit('/test1.dart', (builder) {
+ builder.addSimpleInsertion(0, 'x');
+ });
+ var copy = builder.copy() as ChangeBuilderImpl;
+ await copy.addGenericFileEdit('/test2.dart', (builder) {
+ builder.addSimpleInsertion(0, 'x');
+ });
+ var change = builder.sourceChange;
+ expect(change.edits, hasLength(1));
+ }
+
+ Future<void> test_copy_newLinkedEditGroup() async {
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit('/test.dart', (builder) {
+ builder.addLinkedPosition(SourceRange(1, 2), 'a');
+ });
+ var copy = builder.copy() as ChangeBuilderImpl;
+ await copy.addGenericFileEdit('/test.dart', (builder) {
+ builder.addLinkedPosition(SourceRange(3, 4), 'b');
+ });
+ var change = builder.sourceChange;
+ expect(change.linkedEditGroups, hasLength(1));
+ }
+
+ Future<void> test_copy_newLinkedPosition() async {
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit('/test.dart', (builder) {
+ builder.addLinkedPosition(SourceRange(1, 2), 'a');
+ });
+ var copy = builder.copy() as ChangeBuilderImpl;
+ await copy.addGenericFileEdit('/test.dart', (builder) {
+ builder.addLinkedPosition(SourceRange(3, 4), 'a');
+ });
+ var change = builder.sourceChange;
+ expect(change.linkedEditGroups[0].positions, hasLength(1));
+ }
+
+ Future<void> test_copy_selection() async {
+ var builder = ChangeBuilderImpl();
+ builder.setSelection(Position('/test.dart', 5));
+ var copy = builder.copy() as ChangeBuilderImpl;
+ copy.setSelection(Position('/test.dart', 10));
+ var change = builder.sourceChange;
+ expect(change.selection.offset, 5);
+ }
+
Future<void> test_createFileEditBuilder() async {
var builder = ChangeBuilderImpl();
var path = '/test.dart';
@@ -259,6 +329,71 @@
expect(edits[0].replacement, isEmpty);
}
+ Future<void> test_addDeletion_adjacent_lowerOffsetFirst() async {
+ // TODO(brianwilkerson) This should also merge the deletions, but is written
+ // to ensure that existing uses of FileEditBuilder continue to work even
+ // without that change.
+ var firstOffset = 23;
+ var firstLength = 7;
+ var secondOffset = 30;
+ var secondLength = 5;
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addDeletion(SourceRange(firstOffset, firstLength));
+ builder.addDeletion(SourceRange(secondOffset, secondLength));
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(2));
+ expect(edits[0].offset, secondOffset);
+ expect(edits[0].length, secondLength);
+ expect(edits[0].replacement, isEmpty);
+ expect(edits[1].offset, firstOffset);
+ expect(edits[1].length, firstLength);
+ expect(edits[1].replacement, isEmpty);
+ }
+
+ Future<void> test_addDeletion_adjacent_lowerOffsetSecond() async {
+ // TODO(brianwilkerson) This should also merge the deletions, but is written
+ // to ensure that existing uses of FileEditBuilder continue to work even
+ // without that change.
+ var firstOffset = 23;
+ var firstLength = 7;
+ var secondOffset = 30;
+ var secondLength = 5;
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addDeletion(SourceRange(secondOffset, secondLength));
+ builder.addDeletion(SourceRange(firstOffset, firstLength));
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(2));
+ expect(edits[0].offset, secondOffset);
+ expect(edits[0].length, secondLength);
+ expect(edits[0].replacement, isEmpty);
+ expect(edits[1].offset, firstOffset);
+ expect(edits[1].length, firstLength);
+ expect(edits[1].replacement, isEmpty);
+ }
+
+ @failingTest
+ Future<void> test_addDeletion_overlapping() async {
+ // This support is not yet implemented.
+ var firstOffset = 23;
+ var firstLength = 7;
+ var secondOffset = 27;
+ var secondLength = 8;
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addDeletion(SourceRange(firstOffset, firstLength));
+ builder.addDeletion(SourceRange(secondOffset, secondLength));
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(1));
+ expect(edits[0].offset, firstOffset);
+ expect(edits[0].length, secondOffset + secondLength - firstOffset);
+ expect(edits[0].replacement, isEmpty);
+ }
+
Future<void> test_addInsertion() async {
var builder = ChangeBuilderImpl();
await builder.addGenericFileEdit(path, (builder) {
@@ -307,6 +442,24 @@
expect(edits[0].replacement, text);
}
+ Future<void> test_addSimpleInsertion_sameOffset() async {
+ var offset = 23;
+ var text = 'xyz';
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addSimpleInsertion(offset, text);
+ builder.addSimpleInsertion(offset, 'abc');
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(2));
+ expect(edits[0].offset, offset);
+ expect(edits[0].length, 0);
+ expect(edits[0].replacement, 'abc');
+ expect(edits[1].offset, offset);
+ expect(edits[1].length, 0);
+ expect(edits[1].replacement, text);
+ }
+
Future<void> test_addSimpleReplacement() async {
var offset = 23;
var length = 7;
@@ -322,6 +475,64 @@
expect(edits[0].replacement, text);
}
+ Future<void> test_addSimpleReplacement_adjacent() async {
+ var firstOffset = 23;
+ var firstLength = 7;
+ var secondOffset = firstOffset + firstLength;
+ var secondLength = 5;
+ var text = 'xyz';
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addSimpleReplacement(SourceRange(firstOffset, firstLength), text);
+ builder.addSimpleReplacement(
+ SourceRange(secondOffset, secondLength), text);
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(2));
+ expect(edits[0].offset, secondOffset);
+ expect(edits[0].length, secondLength);
+ expect(edits[0].replacement, text);
+ expect(edits[1].offset, firstOffset);
+ expect(edits[1].length, firstLength);
+ expect(edits[1].replacement, text);
+ }
+
+ Future<void> test_addSimpleReplacement_overlapsHead() async {
+ var offset = 23;
+ var length = 7;
+ var text = 'xyz';
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addSimpleReplacement(SourceRange(offset, length), text);
+ expect(() {
+ builder.addSimpleReplacement(SourceRange(offset - 2, length), text);
+ }, throwsA(isA<ConflictingEditException>()));
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(1));
+ expect(edits[0].offset, offset);
+ expect(edits[0].length, length);
+ expect(edits[0].replacement, text);
+ }
+
+ Future<void> test_addSimpleReplacement_overlapsTail() async {
+ var offset = 23;
+ var length = 7;
+ var text = 'xyz';
+ var builder = ChangeBuilderImpl();
+ await builder.addGenericFileEdit(path, (builder) {
+ builder.addSimpleReplacement(SourceRange(offset, length), text);
+ expect(() {
+ builder.addSimpleReplacement(SourceRange(offset + 2, length), text);
+ }, throwsA(isA<ConflictingEditException>()));
+ });
+ var edits = builder.sourceChange.edits[0].edits;
+ expect(edits, hasLength(1));
+ expect(edits[0].offset, offset);
+ expect(edits[0].length, length);
+ expect(edits[0].replacement, text);
+ }
+
Future<void> test_createEditBuilder() async {
var builder = ChangeBuilderImpl();
await builder.addGenericFileEdit(path, (builder) {
diff --git a/pkg/analyzer_plugin/test/utils/package_root.dart b/pkg/analyzer_plugin/test/utils/package_root.dart
deleted file mode 100644
index 8ef4cfc..0000000
--- a/pkg/analyzer_plugin/test/utils/package_root.dart
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2017, 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';
-
-import 'package:path/path.dart' as pathos;
-
-/// Returns a path to the directory containing source code for packages such as
-/// kernel, front_end, and analyzer.
-String get packageRoot {
- // If the package root directory is specified on the command line using
- // -DpkgRoot=..., use it.
- var pkgRootVar = bool.hasEnvironment('pkgRoot')
- ? const String.fromEnvironment('pkgRoot')
- : null;
- if (pkgRootVar != null) {
- var path = pathos.join(Directory.current.path, pkgRootVar);
- if (!path.endsWith(pathos.separator)) path += pathos.separator;
- return path;
- }
- // Otherwise try to guess based on the script path.
- var scriptPath = pathos.fromUri(Platform.script);
- var parts = pathos.split(scriptPath);
- var pkgIndex = parts.indexOf('pkg');
- if (pkgIndex != -1) {
- return pathos.joinAll(parts.sublist(0, pkgIndex + 1)) + pathos.separator;
- }
- throw StateError('Unable to find sdk/pkg/ in $scriptPath');
-}
diff --git a/pkg/analyzer_plugin/test/verify_tests_test.dart b/pkg/analyzer_plugin/test/verify_tests_test.dart
index 2a05ff6..3ea9290 100644
--- a/pkg/analyzer_plugin/test/verify_tests_test.dart
+++ b/pkg/analyzer_plugin/test/verify_tests_test.dart
@@ -2,84 +2,34 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analysis_tool/package_root.dart' as package_root;
+import 'package:analysis_tool/verify_tests.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:path/path.dart' as path;
-import 'package:test/test.dart';
-
-import 'utils/package_root.dart' as package_root;
void main() {
var provider = PhysicalResourceProvider.INSTANCE;
var packageRoot = provider.pathContext.normalize(package_root.packageRoot);
- var analysisServerPath =
- provider.pathContext.join(packageRoot, 'analyzer_plugin');
- var testDirPath = provider.pathContext.join(analysisServerPath, 'test');
-
- var collection = AnalysisContextCollection(
- includedPaths: <String>[testDirPath], resourceProvider: provider);
- var contexts = collection.contexts;
- if (contexts.length != 1) {
- fail('The test directory contains multiple analysis contexts.');
- }
-
- buildTestsIn(
- contexts[0].currentSession, testDirPath, provider.getFolder(testDirPath));
+ var pathToAnalyze = provider.pathContext.join(packageRoot, 'analyzer_plugin');
+ var testDirPath = provider.pathContext.join(pathToAnalyze, 'test');
+ _VerifyTests(testDirPath).build();
}
-void buildTestsIn(
- AnalysisSession session, String testDirPath, Folder directory) {
- var testFileNames = <String>[];
- File testAllFile;
- var children = directory.getChildren();
- children.sort((first, second) => first.shortName.compareTo(second.shortName));
- for (var child in children) {
- if (child is Folder) {
- if (child.shortName == 'integration') {
- continue;
- } else if (child.getChildAssumingFile('test_all.dart').exists) {
- testFileNames.add('${child.shortName}/test_all.dart');
- }
- buildTestsIn(session, testDirPath, child);
- } else if (child is File) {
- var name = child.shortName;
- if (name == 'test_all.dart') {
- testAllFile = child;
- } else if (name.endsWith('_test.dart')) {
- testFileNames.add(name);
- }
+class _VerifyTests extends VerifyTests {
+ _VerifyTests(String testDirPath, {List<String> excludedPaths})
+ : super(testDirPath, excludedPaths: excludedPaths);
+
+ @override
+ bool isExpensive(Resource resource) => resource.shortName == 'integration';
+
+ @override
+ bool isOkAsAdditionalTestAllImport(Folder folder, String uri) {
+ if (folder.path == testDirPath &&
+ uri == '../tool/spec/check_all_test.dart') {
+ // The topmost `test_all.dart` also runs this one test in `tool` for
+ // convenience.
+ return true;
}
+ return super.isOkAsAdditionalTestAllImport(folder, uri);
}
- var relativePath = path.relative(directory.path, from: testDirPath);
- test(relativePath, () {
- if (testFileNames.isEmpty) {
- return;
- }
- if (testAllFile == null) {
- fail('Missing "test_all.dart" in $relativePath');
- }
- var result = session.getParsedUnit(testAllFile.path);
- if (result.state != ResultState.VALID) {
- fail('Could not parse ${testAllFile.path}');
- }
- var importedFiles = <String>[];
- for (var directive in result.unit.directives) {
- if (directive is ImportDirective) {
- importedFiles.add(directive.uri.stringValue);
- }
- }
- var missingFiles = <String>[];
- for (var testFileName in testFileNames) {
- if (!importedFiles.contains(testFileName)) {
- missingFiles.add(testFileName);
- }
- }
- if (missingFiles.isNotEmpty) {
- fail('Tests missing from "test_all.dart": ${missingFiles.join(', ')}');
- }
- });
}
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 7b7387c..8d84fe7 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -595,6 +595,13 @@
/// compilation.
bool isNamedListConstructor(String name, ConstructorEntity element);
+ /// Returns `true` if [element] is the named constructor of `JSArray`,
+ /// e.g. `JSArray.fixed`.
+ ///
+ /// This will not resolve the constructor if it hasn't been seen yet during
+ /// compilation.
+ bool isNamedJSArrayConstructor(String name, ConstructorEntity element);
+
bool isDefaultEqualityImplementation(MemberEntity element);
/// Returns `true` if [selector] applies to `JSIndexable.length`.
@@ -885,6 +892,14 @@
bool isNamedListConstructor(String name, ConstructorEntity element) =>
element.name == name && element.enclosingClass == listClass;
+ /// Returns `true` if [element] is the [name]d constructor of `JSArray`.
+ ///
+ /// This will not resolve the constructor if it hasn't been seen yet during
+ /// compilation.
+ @override
+ bool isNamedJSArrayConstructor(String name, ConstructorEntity element) =>
+ element.name == name && element.enclosingClass == jsArrayClass;
+
@override
DynamicType get dynamicType => _env.dynamicType;
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index afc24a3..55d7ab6 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -1296,10 +1296,11 @@
// We have something like `List.empty(growable: true)`.
TypeInformation baseType =
_listBaseType(arguments, defaultGrowable: false);
+ TypeInformation elementType = _types.nonNullEmpty(); // No elements!
return _inferrer.concreteTypes.putIfAbsent(
node,
() => _types.allocateList(
- baseType, node, _analyzedMember, _types.nonNullEmpty(), 0));
+ baseType, node, _analyzedMember, elementType, 0));
}
if (commonElements.isNamedListConstructor('of', constructor) ||
commonElements.isNamedListConstructor('from', constructor)) {
@@ -1314,6 +1315,44 @@
() => _types.allocateList(
baseType, node, _analyzedMember, elementType));
}
+
+ // `JSArray.fixed` corresponds to `new Array(length)`, which is a list
+ // filled with `null`.
+ if (commonElements.isNamedJSArrayConstructor('fixed', constructor)) {
+ int length = _findLength(arguments);
+ TypeInformation elementType = _types.nullType;
+ return _inferrer.concreteTypes.putIfAbsent(
+ node,
+ () => _types.allocateList(_types.fixedListType, node, _analyzedMember,
+ elementType, length));
+ }
+
+ // `JSArray.allocateFixed` creates an array with 'no elements'. The contract
+ // is that the caller will assign a value to each member before any element
+ // is accessed. We can start tracking the element type as 'bottom'.
+ if (commonElements.isNamedJSArrayConstructor(
+ 'allocateFixed', constructor)) {
+ int length = _findLength(arguments);
+ TypeInformation elementType = _types.nonNullEmpty();
+ return _inferrer.concreteTypes.putIfAbsent(
+ node,
+ () => _types.allocateList(_types.fixedListType, node, _analyzedMember,
+ elementType, length));
+ }
+
+ // `JSArray.allocateGrowable` creates an array with 'no elements'. The
+ // contract is that the caller will assign a value to each member before any
+ // element is accessed. We can start tracking the element type as 'bottom'.
+ if (commonElements.isNamedJSArrayConstructor(
+ 'allocateGrowable', constructor)) {
+ int length = _findLength(arguments);
+ TypeInformation elementType = _types.nonNullEmpty();
+ return _inferrer.concreteTypes.putIfAbsent(
+ node,
+ () => _types.allocateList(_types.growableListType, node,
+ _analyzedMember, elementType, length));
+ }
+
if (_isConstructorOfTypedArraySubclass(constructor)) {
// We have something like `Uint32List(len)`.
int length = _findLength(arguments);
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 07cb160..ce387d5 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -17,6 +17,7 @@
import 'package:kernel/target/targets.dart';
import 'invocation_mirror_constants.dart';
+import 'transformations/lowering.dart' as lowering show transformLibraries;
const Iterable<String> _allowedDartSchemePaths = const <String>[
'async',
@@ -66,7 +67,7 @@
bool get enableNoSuchMethodForwarders => true;
@override
- bool get supportsLateFields => false;
+ int get enabledLateLowerings => LateLowering.all;
@override
bool get supportsLateLoweringSentinel => false;
@@ -83,6 +84,12 @@
List<String> get extraRequiredLibraries => _requiredLibraries[name];
@override
+ List<String> get extraIndexedLibraries => const [
+ 'dart:_interceptors',
+ 'dart:_js_helper',
+ ];
+
+ @override
bool mayDefineRestrictedType(Uri uri) =>
uri.scheme == 'dart' &&
(uri.path == 'core' || uri.path == '_interceptors');
@@ -118,6 +125,9 @@
diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>)
.visitLibrary(library);
}
+ lowering.transformLibraries(
+ libraries, coreTypes, hierarchy, flags.enableNullSafety);
+ logger?.call("Lowering transformations performed");
}
@override
diff --git a/pkg/compiler/lib/src/kernel/transformations/factory_specializer.dart b/pkg/compiler/lib/src/kernel/transformations/factory_specializer.dart
new file mode 100644
index 0000000..ebc00ae
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/transformations/factory_specializer.dart
@@ -0,0 +1,39 @@
+// 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:kernel/kernel.dart';
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+import 'package:kernel/core_types.dart';
+import 'list_factory_specializer.dart';
+
+typedef SpecializerTransformer = TreeNode Function(
+ StaticInvocation node, Member contextMember);
+
+abstract class BaseSpecializer {
+ // Populated in constructors of subclasses.
+ final Map<Member, SpecializerTransformer> transformers = {};
+}
+
+class FactorySpecializer extends BaseSpecializer {
+ final ListFactorySpecializer _listFactorySpecializer;
+
+ FactorySpecializer(CoreTypes coreTypes, ClassHierarchy hierarchy)
+ : _listFactorySpecializer = ListFactorySpecializer(coreTypes, hierarchy) {
+ transformers.addAll(_listFactorySpecializer.transformers);
+ }
+
+ TreeNode transformStaticInvocation(
+ StaticInvocation invocation, Member contextMember) {
+ final target = invocation.target;
+ if (target == null) {
+ return invocation;
+ }
+
+ final transformer = transformers[target];
+ if (transformer != null) {
+ return transformer(invocation, contextMember);
+ }
+ return invocation;
+ }
+}
diff --git a/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.dart b/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.dart
new file mode 100644
index 0000000..e61d1dd
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/transformations/list_factory_specializer.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:kernel/ast.dart';
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+import 'package:kernel/clone.dart' show CloneVisitorNotMembers;
+import 'package:kernel/core_types.dart' show CoreTypes;
+import 'factory_specializer.dart';
+
+/// Replaces invocation of List factory constructors.
+///
+/// Expands `List.generate` to a loop when the function argument is a function
+/// expression (immediate closure).
+///
+class ListFactorySpecializer extends BaseSpecializer {
+ final CoreTypes coreTypes;
+ final ClassHierarchy hierarchy;
+
+ final Class _intClass;
+ final Class _jsArrayClass;
+ final Procedure _listGenerateFactory;
+ final Procedure _arrayAllocateFixedFactory;
+ final Procedure _arrayAllocateGrowableFactory;
+
+ ListFactorySpecializer(this.coreTypes, this.hierarchy)
+ : _listGenerateFactory =
+ coreTypes.index.getMember('dart:core', 'List', 'generate'),
+ _arrayAllocateFixedFactory = coreTypes.index
+ .getMember('dart:_interceptors', 'JSArray', 'allocateFixed'),
+ _arrayAllocateGrowableFactory = coreTypes.index
+ .getMember('dart:_interceptors', 'JSArray', 'allocateGrowable'),
+ _jsArrayClass =
+ coreTypes.index.getClass('dart:_interceptors', 'JSArray'),
+ _intClass = coreTypes.index.getClass('dart:core', 'int') {
+ assert(_listGenerateFactory.isFactory);
+ assert(_arrayAllocateGrowableFactory.isFactory);
+ assert(_arrayAllocateFixedFactory.isFactory);
+ transformers.addAll({
+ _listGenerateFactory: transformListGenerateFactory,
+ });
+ }
+
+ Member _intPlus;
+ Member get intPlus =>
+ _intPlus ??= hierarchy.getInterfaceMember(_intClass, Name('+'));
+
+ Member _intLess;
+ Member get intLess =>
+ _intLess ??= hierarchy.getInterfaceMember(_intClass, Name('<'));
+
+ Member _jsArrayIndexSet;
+ Member get jsArrayIndexSet => _jsArrayIndexSet ??=
+ hierarchy.getInterfaceMember(_jsArrayClass, Name('[]='));
+
+ /// Replace calls to `List.generate(length, (i) => e)` with an expansion
+ ///
+ /// BlockExpression
+ /// Block
+ /// var _length = <length>;
+ /// var _list = List.allocate(_length);
+ /// for (var _i = 0; _i < _length; _i++) {
+ /// _list[_i] = e;
+ /// }
+ /// => _list
+ ///
+ /// Declines to expand if:
+ /// - the function argument is not a simple closure,
+ /// - the `growable:` argument cannot be determined.
+ TreeNode transformListGenerateFactory(
+ StaticInvocation node, Member contextMember) {
+ final args = node.arguments;
+ assert(args.positional.length == 2);
+ final length = args.positional[0];
+ final generator = args.positional[1];
+ final bool growable =
+ _getConstantNamedOptionalArgument(args, 'growable', true);
+ if (growable == null) return node;
+
+ if (generator is! FunctionExpression) return node;
+
+ if (!ListGenerateLoopBodyInliner.suitableFunctionExpression(generator)) {
+ return node;
+ }
+
+ final intType = contextMember.isNonNullableByDefault
+ ? coreTypes.intLegacyRawType
+ : coreTypes.intNonNullableRawType;
+
+ // If the length is a constant, use the constant directly so that the
+ // inferrer can see the constant length.
+ int /*?*/ lengthConstant = _getLengthArgument(args);
+ VariableDeclaration lengthVariable;
+
+ Expression getLength() {
+ if (lengthConstant != null) return IntLiteral(lengthConstant);
+ lengthVariable ??= VariableDeclaration('_length',
+ initializer: length, isFinal: true, type: intType)
+ ..fileOffset = node.fileOffset;
+ return VariableGet(lengthVariable)..fileOffset = node.fileOffset;
+ }
+
+ TreeNode allocation = StaticInvocation(
+ growable ? _arrayAllocateGrowableFactory : _arrayAllocateFixedFactory,
+ Arguments(
+ [getLength()],
+ types: args.types,
+ ))
+ ..fileOffset = node.fileOffset;
+
+ final listVariable = VariableDeclaration(
+ _listNameFromContext(node),
+ initializer: allocation,
+ isFinal: true,
+ type: InterfaceType(
+ _jsArrayClass, Nullability.nonNullable, [...args.types]),
+ )..fileOffset = node.fileOffset;
+
+ final indexVariable = VariableDeclaration(
+ _indexNameFromContext(generator),
+ initializer: IntLiteral(0),
+ type: intType,
+ )..fileOffset = node.fileOffset;
+ indexVariable.fileOffset = (generator as FunctionExpression)
+ .function
+ .positionalParameters
+ .first
+ .fileOffset;
+
+ final loop = ForStatement(
+ // initializers: _i = 0
+ [indexVariable],
+ // condition: _i < _length
+ MethodInvocation(
+ VariableGet(indexVariable)..fileOffset = node.fileOffset,
+ Name('<'),
+ Arguments([getLength()]),
+ )..interfaceTarget = intLess,
+ // updates: _i++
+ [
+ VariableSet(
+ indexVariable,
+ MethodInvocation(
+ VariableGet(indexVariable)..fileOffset = node.fileOffset,
+ Name('+'),
+ Arguments([IntLiteral(1)]),
+ )..interfaceTarget = intPlus,
+ )..fileOffset = node.fileOffset,
+ ],
+ // body, e.g. _list[_i] = expression;
+ _loopBody(node.fileOffset, listVariable, indexVariable, generator),
+ )..fileOffset = node.fileOffset;
+
+ return BlockExpression(
+ Block([
+ if (lengthVariable != null) lengthVariable,
+ listVariable,
+ loop,
+ ]),
+ VariableGet(listVariable)..fileOffset = node.fileOffset,
+ );
+ }
+
+ Statement _loopBody(
+ int constructorFileOffset,
+ VariableDeclaration listVariable,
+ VariableDeclaration indexVariable,
+ FunctionExpression generator) {
+ final inliner = ListGenerateLoopBodyInliner(
+ this, constructorFileOffset, listVariable, generator.function);
+ inliner.bind(indexVariable);
+ return inliner.run();
+ }
+
+ /// Returns constant value of the first argument in [args], or null if it is
+ /// not a constant.
+ int /*?*/ _getLengthArgument(Arguments args) {
+ if (args.positional.length < 1) return null;
+ final value = args.positional.first;
+ if (value is IntLiteral) {
+ return value.value;
+ } else if (value is ConstantExpression) {
+ final constant = value.constant;
+ if (constant is IntConstant) {
+ return constant.value;
+ }
+ }
+ return null;
+ }
+
+ /// Returns constant value of the only named optional argument in [args], or
+ /// null if it is not a bool constant. Returns [defaultValue] if optional
+ /// argument is not passed. Argument is asserted to have the given [name].
+ bool /*?*/ _getConstantNamedOptionalArgument(
+ Arguments args, String name, bool defaultValue) {
+ if (args.named.isEmpty) {
+ return defaultValue;
+ }
+ final namedArg = args.named.single;
+ assert(namedArg.name == name);
+ final value = namedArg.value;
+ if (value is BoolLiteral) {
+ return value.value;
+ } else if (value is ConstantExpression) {
+ final constant = value.constant;
+ if (constant is BoolConstant) {
+ return constant.value;
+ }
+ }
+ return null;
+ }
+
+ /// Choose a name for the `_list` temporary. If the `List.generate` expression
+ /// is an initializer for a variable, use that name so that dart2js can try to
+ /// use one JavaScript variable with the source name for 'both' variables.
+ String _listNameFromContext(Expression node) {
+ TreeNode parent = node.parent;
+ if (parent is VariableDeclaration) return parent.name;
+ return '_list';
+ }
+
+ String _indexNameFromContext(FunctionExpression generator) {
+ final function = generator.function;
+ String /*?*/ candidate = function.positionalParameters.first.name;
+ if (candidate == null || candidate == '' || candidate == '_') return '_i';
+ return candidate;
+ }
+}
+
+/// Inliner for function expressions of `List.generate` calls.
+class ListGenerateLoopBodyInliner extends CloneVisitorNotMembers {
+ final ListFactorySpecializer listFactorySpecializer;
+
+ /// Offset for the constructor call, used for all nodes that carry the value of the list.
+ final int constructorFileOffset;
+ final VariableDeclaration listVariable;
+ final FunctionNode function;
+ VariableDeclaration argument;
+ VariableDeclaration parameter;
+ int functionNestingLevel = 0;
+
+ ListGenerateLoopBodyInliner(this.listFactorySpecializer,
+ this.constructorFileOffset, this.listVariable, this.function);
+
+ static bool suitableFunctionExpression(FunctionExpression node) {
+ final function = node.function;
+ // These conditions should be satisfied by language rules.
+ if (function.typeParameters.isNotEmpty) return false;
+ if (function.requiredParameterCount != 1) return false;
+ if (function.positionalParameters.length != 1) return false;
+ if (function.namedParameters.isNotEmpty) return false;
+
+ final body = function.body;
+ // For now, only arrow functions.
+ if (body is ReturnStatement) return true;
+
+ return false;
+ }
+
+ void bind(VariableDeclaration argument) {
+ // The [argument] is the loop index variable. In the general case this needs
+ // to be copied to a variable for the closure parameter as that is a
+ // separate location that may be mutated. In the usual case the closure
+ // parameter is not modified. We use the same name for the parameter and
+ // argument to help dart2js allocate both locations to the same JavaScript
+ // variable. The argument is usually named after the closure parameter.
+ final closureParameter = function.positionalParameters.single;
+ parameter = VariableDeclaration(argument.name,
+ initializer: VariableGet(argument)..fileOffset = argument.fileOffset,
+ type: closureParameter.type)
+ ..fileOffset = closureParameter.fileOffset;
+ this.argument = argument;
+ variables[closureParameter] = parameter;
+ }
+
+ Statement run() {
+ final body = cloneInContext(function.body);
+ return Block([parameter, body]);
+ }
+
+ @override
+ visitReturnStatement(ReturnStatement node) {
+ // Do the default for return statements in nested functions.
+ if (functionNestingLevel > 0) return super.visitReturnStatement(node);
+
+ // We don't use a variable for the returned value. In the simple case it is
+ // not necessary, and it is not clear that the rules for definite assignment
+ // are not a perfect match for the locations of return statements. Instead
+ // we expand
+ //
+ // return expression;
+ //
+ // to
+ //
+ // list[index] = expression;
+ //
+ // TODO(sra): Currently this inliner accepts only arrow functions (a single
+ // return). If a wider variety is accepted, we might need to break after the
+ // assignment to 'exit' the inlined code.
+
+ final expression = node.expression;
+ final value = expression == null ? NullLiteral() : clone(expression);
+ // TODO(sra): Indicate that this indexed setter is safe.
+ return ExpressionStatement(
+ MethodInvocation(
+ VariableGet(listVariable)..fileOffset = constructorFileOffset,
+ Name('[]='),
+ Arguments([
+ VariableGet(argument)..fileOffset = node.fileOffset,
+ value,
+ ]),
+ )
+ ..interfaceTarget = listFactorySpecializer.jsArrayIndexSet
+ ..isInvariant = true
+ ..isBoundsSafe = true
+ ..fileOffset = constructorFileOffset,
+ );
+ }
+
+ /// Nested functions.
+ @override
+ visitFunctionNode(FunctionNode node) {
+ functionNestingLevel++;
+ final cloned = super.visitFunctionNode(node);
+ functionNestingLevel--;
+ return cloned;
+ }
+
+ @override
+ visitVariableGet(VariableGet node) {
+ // Unmapped variables are from an outer scope.
+ var mapped = variables[node.variable] ?? node.variable;
+ return VariableGet(mapped, visitOptionalType(node.promotedType))
+ ..fileOffset = node.fileOffset;
+ }
+
+ @override
+ visitVariableSet(VariableSet node) {
+ // Unmapped variables are from an outer scope.
+ var mapped = variables[node.variable] ?? node.variable;
+ return VariableSet(mapped, clone(node.value))..fileOffset = node.fileOffset;
+ }
+}
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
new file mode 100644
index 0000000..72c4f15
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/transformations/lowering.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.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/type_environment.dart'
+ show StaticTypeContext, TypeEnvironment;
+import 'factory_specializer.dart';
+
+/// dart2js-specific lowering transformations and optimizations combined into a
+/// single transformation pass.
+///
+/// Each transformation is applied locally to AST nodes of certain types after
+/// transforming children nodes.
+void transformLibraries(List<Library> libraries, CoreTypes coreTypes,
+ ClassHierarchy hierarchy, bool nullSafety) {
+ final transformer = _Lowering(coreTypes, hierarchy, nullSafety);
+ libraries.forEach(transformer.visitLibrary);
+}
+
+class _Lowering extends Transformer {
+ final TypeEnvironment env;
+ final bool nullSafety;
+ final FactorySpecializer factorySpecializer;
+
+ Member _currentMember;
+ StaticTypeContext _cachedStaticTypeContext;
+
+ _Lowering(CoreTypes coreTypes, ClassHierarchy hierarchy, this.nullSafety)
+ : env = TypeEnvironment(coreTypes, hierarchy),
+ factorySpecializer = FactorySpecializer(coreTypes, hierarchy);
+
+ // ignore: unused_element
+ StaticTypeContext get _staticTypeContext =>
+ _cachedStaticTypeContext ??= StaticTypeContext(_currentMember, env);
+
+ @override
+ defaultMember(Member node) {
+ _currentMember = node;
+ _cachedStaticTypeContext = null;
+
+ final result = super.defaultMember(node);
+
+ _currentMember = null;
+ _cachedStaticTypeContext = null;
+ return result;
+ }
+
+ @override
+ visitStaticInvocation(StaticInvocation node) {
+ node.transformChildren(this);
+ return factorySpecializer.transformStaticInvocation(node, _currentMember);
+ }
+}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index fb0b04b..1032865 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -3882,7 +3882,10 @@
if (_abstractValueDomain.isFixedArray(resultType).isDefinitelyTrue) {
// These constructors all take a length as the first argument.
if (_commonElements.isNamedListConstructor('filled', function) ||
- _commonElements.isNamedListConstructor('generate', function)) {
+ _commonElements.isNamedListConstructor('generate', function) ||
+ _commonElements.isNamedJSArrayConstructor('fixed', function) ||
+ _commonElements.isNamedJSArrayConstructor(
+ 'allocateFixed', function)) {
isFixedList = true;
}
}
@@ -4963,22 +4966,28 @@
AbstractValue resultType =
_typeInferenceMap.resultTypeOfSelector(selector, receiverType);
+ HInvokeDynamic invoke;
if (selector.isGetter) {
- push(new HInvokeDynamicGetter(selector, receiverType, element, inputs,
- isIntercepted, resultType, sourceInformation));
+ invoke = HInvokeDynamicGetter(selector, receiverType, element, inputs,
+ isIntercepted, resultType, sourceInformation);
} else if (selector.isSetter) {
- push(new HInvokeDynamicSetter(selector, receiverType, element, inputs,
- isIntercepted, resultType, sourceInformation));
+ invoke = HInvokeDynamicSetter(selector, receiverType, element, inputs,
+ isIntercepted, resultType, sourceInformation);
} else if (selector.isClosureCall) {
assert(!isIntercepted);
- push(new HInvokeClosure(
+ invoke = HInvokeClosure(
selector, receiverType, inputs, resultType, typeArguments)
- ..sourceInformation = sourceInformation);
+ ..sourceInformation = sourceInformation;
} else {
- push(new HInvokeDynamicMethod(selector, receiverType, inputs, resultType,
+ invoke = HInvokeDynamicMethod(selector, receiverType, inputs, resultType,
typeArguments, sourceInformation,
- isIntercepted: isIntercepted));
+ isIntercepted: isIntercepted);
}
+ if (node is ir.MethodInvocation) {
+ invoke.isInvariant = node.isInvariant;
+ invoke.isBoundsSafe = node.isBoundsSafe;
+ }
+ push(invoke);
}
HInstruction _invokeJsInteropFunction(
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index 49e534a..92745f6 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
@@ -192,6 +192,9 @@
HInstruction value,
JCommonElements commonElements,
JClosedWorld closedWorld) {
+ if (instruction.isInvariant) {
+ return true;
+ }
// Handle typed arrays by recognizing the exact implementation of `[]=` and
// checking if [value] has the appropriate type.
if (instruction.element != null) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 6a551f89..77c24d3 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -1709,6 +1709,17 @@
AbstractValue _receiverType;
final AbstractValue _originalReceiverType;
+ /// `true` if the type parameters at the call known to be invariant with
+ /// respect to the type parameters of the receiver instance. This corresponds
+ /// to the [ir.MethodInvocation.isInvariant] property and may be updated with
+ /// additional analysis.
+ bool isInvariant = false;
+
+ /// `true` for an indexed getter or setter if the index is known to be in
+ /// range. This corresponds to the [ir.MethodInvocation.isBoundsSafe] property
+ /// but and may updated with additional analysis.
+ bool isBoundsSafe = false;
+
// Cached target when non-nullable receiver type and selector determine a
// single target. This is in effect a direct call (except for a possible
// `null` receiver). The element should only be set if the inputs are correct
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index aff9860..ad03cf6 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -679,12 +679,15 @@
if (applies(commonElements.jsArrayRemoveLast)) {
target = commonElements.jsArrayRemoveLast;
} else if (applies(commonElements.jsArrayAdd)) {
- // The codegen special cases array calls, but does not
- // inline argument type checks.
- if (!_closedWorld.annotationsData
+ // Codegen special cases array calls to `Array.push`, but does not
+ // inline argument type checks. We lower if the check always passes
+ // (due to invariance or being a top-type), or if the check is not
+ // emitted.
+ if (node.isInvariant ||
+ input is HLiteralList ||
+ !_closedWorld.annotationsData
.getParameterCheckPolicy(commonElements.jsArrayAdd)
- .isEmitted ||
- input is HLiteralList) {
+ .isEmitted) {
target = commonElements.jsArrayAdd;
}
}
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 58607bb..6a7ec65 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -34,6 +34,7 @@
package_config: any
path: any
source_maps: any
+ test: any
# Unpublished packages that can be used via path dependency
async_helper:
path: ../async_helper
diff --git a/pkg/compiler/test/inference/data/list2.dart b/pkg/compiler/test/inference/data/list2.dart
index 16b21d8..81d7d8f 100644
--- a/pkg/compiler/test/inference/data/list2.dart
+++ b/pkg/compiler/test/inference/data/list2.dart
@@ -23,6 +23,7 @@
listGenerateGrowable,
listGenerateFixed,
listGenerateEither,
+ listGenerateBigClosure,
listOfDefault,
listOfGrowable,
listOfFixed,
@@ -72,24 +73,37 @@
// -------- List.generate --------
/*member: listGenerateDefault:Container([exact=JSExtendableArray], element: [exact=JSString], length: 8)*/
-get listGenerateDefault => List.generate(
- 8, /*[exact=JSString]*/ (/*[subclass=JSPositiveInt]*/ i) => 'x$i');
+get listGenerateDefault => List
+ . /*update: Container([exact=JSExtendableArray], element: [exact=JSString], length: 8)*/ generate(
+ 8, (i) => 'x$i');
/*member: listGenerateGrowable:Container([exact=JSExtendableArray], element: [exact=JSString], length: 8)*/
-get listGenerateGrowable => List.generate(
- 8, /*[exact=JSString]*/ (/*[subclass=JSPositiveInt]*/ i) => 'g$i',
- growable: true);
+get listGenerateGrowable => List
+ . /*update: Container([exact=JSExtendableArray], element: [exact=JSString], length: 8)*/ generate(
+ 8, (i) => 'g$i',
+ growable: true);
/*member: listGenerateFixed:Container([exact=JSFixedArray], element: [exact=JSString], length: 8)*/
-get listGenerateFixed => List.generate(
- 8, /*[exact=JSString]*/ (/*[subclass=JSPositiveInt]*/ i) => 'f$i',
- growable: false);
+get listGenerateFixed => List
+ . /*update: Container([exact=JSFixedArray], element: [exact=JSString], length: 8)*/ generate(
+ 8, (i) => 'f$i',
+ growable: false);
/*member: listGenerateEither:Container([subclass=JSMutableArray], element: [exact=JSString], length: 8)*/
get listGenerateEither => List.generate(
8, /*[exact=JSString]*/ (/*[subclass=JSPositiveInt]*/ i) => 'e$i',
growable: boolFlag);
+/*member: listGenerateBigClosure:Container([exact=JSExtendableArray], element: [exact=JSString], length: 8)*/
+get listGenerateBigClosure => List.generate(
+ 8,
+ /*[exact=JSString]*/ (/*[subclass=JSPositiveInt]*/ i) {
+ if (i /*invoke: [subclass=JSPositiveInt]*/ == 1) return 'one';
+ if (i /*invoke: [subclass=JSPositiveInt]*/ == 2) return 'two';
+ return '$i';
+ },
+ );
+
// -------- List.of --------
/*member: listOfDefault:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/
diff --git a/pkg/compiler/test/kernel/common_test_utils.dart b/pkg/compiler/test/kernel/common_test_utils.dart
new file mode 100644
index 0000000..ed7c9e5
--- /dev/null
+++ b/pkg/compiler/test/kernel/common_test_utils.dart
@@ -0,0 +1,135 @@
+// 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:async';
+import 'dart:io';
+
+import 'package:front_end/src/api_unstable/dart2js.dart'
+ show
+ CompilerOptions,
+ DiagnosticMessage,
+ computePlatformBinariesLocation,
+ kernelForProgram,
+ parseExperimentalArguments,
+ parseExperimentalFlags;
+import 'package:kernel/ast.dart';
+import 'package:kernel/text/ast_to_text.dart' show Printer;
+import 'package:kernel/target/targets.dart';
+import 'package:test/test.dart';
+
+import 'package:compiler/src/kernel/dart2js_target.dart' show Dart2jsTarget;
+
+/// Environment define to update expectation files on failures.
+const kUpdateExpectations = 'updateExpectations';
+
+/// Environment define to dump actual results alongside expectations.
+const kDumpActualResult = 'dump.actual.result';
+
+class TestingDart2jsTarget extends Dart2jsTarget {
+ TestingDart2jsTarget(TargetFlags flags) : super('dart2js', flags);
+}
+
+Future<Component> compileTestCaseToKernelProgram(Uri sourceUri,
+ {Target target,
+ bool enableSuperMixins = false,
+ List<String> experimentalFlags,
+ Map<String, String> environmentDefines}) async {
+ final platformKernel =
+ computePlatformBinariesLocation().resolve('dart2js_platform.dill');
+ target ??= TestingDart2jsTarget(TargetFlags());
+ environmentDefines ??= <String, String>{};
+ final options = CompilerOptions()
+ ..target = target
+ ..additionalDills = <Uri>[platformKernel]
+ ..environmentDefines = environmentDefines
+ ..explicitExperimentalFlags =
+ parseExperimentalFlags(parseExperimentalArguments(experimentalFlags),
+ onError: (String message) {
+ throw message;
+ })
+ ..onDiagnostic = (DiagnosticMessage message) {
+ fail("Compilation error: ${message.plainTextFormatted.join('\n')}");
+ };
+
+ final Component component =
+ (await kernelForProgram(sourceUri, options)).component;
+
+ // Make sure the library name is the same and does not depend on the order
+ // of test cases.
+ component.mainMethod.enclosingLibrary.name = '#lib';
+
+ return component;
+}
+
+String kernelLibraryToString(Library library) {
+ final buffer = StringBuffer();
+ Printer(buffer, showMetadata: true).writeLibraryFile(library);
+ return buffer
+ .toString()
+ .replaceAll(library.importUri.toString(), library.name);
+}
+
+String kernelComponentToString(Component component) {
+ final buffer = StringBuffer();
+ Printer(buffer, showMetadata: true).writeComponentFile(component);
+ final mainLibrary = component.mainMethod.enclosingLibrary;
+ return buffer
+ .toString()
+ .replaceAll(mainLibrary.importUri.toString(), mainLibrary.name);
+}
+
+class Difference {
+ final int line;
+ final String actual;
+ final String expected;
+
+ Difference(this.line, this.actual, this.expected);
+}
+
+Difference findFirstDifference(String actual, String expected) {
+ final actualLines = actual.split('\n');
+ final expectedLines = expected.split('\n');
+ int i = 0;
+ for (; i < actualLines.length && i < expectedLines.length; ++i) {
+ if (actualLines[i] != expectedLines[i]) {
+ return Difference(i + 1, actualLines[i], expectedLines[i]);
+ }
+ }
+ return Difference(i + 1, i < actualLines.length ? actualLines[i] : '<END>',
+ i < expectedLines.length ? expectedLines[i] : '<END>');
+}
+
+void compareResultWithExpectationsFile(Uri source, String actual) {
+ final expectFile = File(source.toFilePath() + '.expect');
+ final expected = expectFile.existsSync() ? expectFile.readAsStringSync() : '';
+
+ if (actual != expected) {
+ if (bool.fromEnvironment(kUpdateExpectations)) {
+ expectFile.writeAsStringSync(actual);
+ print(" Updated $expectFile");
+ } else {
+ if (bool.fromEnvironment(kDumpActualResult)) {
+ File(source.toFilePath() + '.actual').writeAsStringSync(actual);
+ }
+ Difference diff = findFirstDifference(actual, expected);
+ fail("""
+
+Result is different for the test case $source
+
+The first difference is at line ${diff.line}.
+Actual: ${diff.actual}
+Expected: ${diff.expected}
+
+This failure can be caused by changes in the front-end if it starts generating
+different kernel AST for the same Dart programs.
+
+In order to re-generate expectations run tests with -D$kUpdateExpectations=true VM option:
+
+ sdk/bin/dart -D$kUpdateExpectations=true pkg/compiler/test/kernel/goldens_test.dart
+
+In order to dump actual results into .actual files run tests with -D$kDumpActualResult=true VM option.
+""");
+ }
+ }
+}
diff --git a/pkg/compiler/test/kernel/data/list_generate_1.dart b/pkg/compiler/test/kernel/data/list_generate_1.dart
new file mode 100644
index 0000000..3365cf5
--- /dev/null
+++ b/pkg/compiler/test/kernel/data/list_generate_1.dart
@@ -0,0 +1,15 @@
+// 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.
+
+var list1 = List<int>.generate(10, (i) => i);
+var list2 = List<int>.generate(10, (i) => i, growable: true);
+var list3 = List<int>.generate(10, (i) => i, growable: false);
+var list4 = List<int>.generate(10, (i) => i, growable: someGrowable);
+
+bool someGrowable = true;
+
+void main() {
+ someGrowable = !someGrowable;
+ print([list1, list2, list3, list4]);
+}
diff --git a/pkg/compiler/test/kernel/data/list_generate_1.dart.expect b/pkg/compiler/test/kernel/data/list_generate_1.dart.expect
new file mode 100644
index 0000000..be2484b
--- /dev/null
+++ b/pkg/compiler/test/kernel/data/list_generate_1.dart.expect
@@ -0,0 +1,32 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+import "dart:_interceptors" as _in;
+
+static field core::List<core::int*>* list1 = block {
+ final _in::JSArray<core::int*> _list = _in::JSArray::allocateGrowable<core::int*>(10);
+ for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::int* i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, i);
+ }
+} =>_list;
+static field core::List<core::int*>* list2 = block {
+ final _in::JSArray<core::int*> _list = _in::JSArray::allocateGrowable<core::int*>(10);
+ for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::int* i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, i);
+ }
+} =>_list;
+static field core::List<core::int*>* list3 = block {
+ final _in::JSArray<core::int*> _list = _in::JSArray::allocateFixed<core::int*>(10);
+ for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::int* i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, i);
+ }
+} =>_list;
+static field core::List<core::int*>* list4 = core::List::generate<core::int*>(10, (core::int* i) → core::int* => i, growable: self::someGrowable);
+static field core::bool* someGrowable = true;
+static method main() → void {
+ self::someGrowable = !self::someGrowable;
+ core::print(<core::List<core::int*>*>[self::list1, self::list2, self::list3, self::list4]);
+}
diff --git a/pkg/compiler/test/kernel/data/list_generate_2.dart b/pkg/compiler/test/kernel/data/list_generate_2.dart
new file mode 100644
index 0000000..af9196d
--- /dev/null
+++ b/pkg/compiler/test/kernel/data/list_generate_2.dart
@@ -0,0 +1,8 @@
+// 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.
+
+void main() {
+ // 'nested' List.generate calls.
+ print(List.generate(10, (i) => List.generate(i, (i) => i + 1)));
+}
diff --git a/pkg/compiler/test/kernel/data/list_generate_2.dart.expect b/pkg/compiler/test/kernel/data/list_generate_2.dart.expect
new file mode 100644
index 0000000..e2a2196
--- /dev/null
+++ b/pkg/compiler/test/kernel/data/list_generate_2.dart.expect
@@ -0,0 +1,21 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+import "dart:_interceptors" as _in;
+
+static method main() → void {
+ core::print( block {
+ final _in::JSArray<core::List<core::int*>*> _list = _in::JSArray::allocateGrowable<core::List<core::int*>*>(10);
+ for (core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::int* i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, block {
+ final core::int _length = i;
+ final _in::JSArray<core::int*> _list = _in::JSArray::allocateGrowable<core::int*>(_length);
+ for (core::int i = 0; i.{core::num::<}(_length); i = i.{core::num::+}(1)) {
+ core::int* i = i;
+ _list.{_in::JSArray::[]=}{Invariant,BoundsSafe}(i, i.{core::num::+}(1));
+ }
+ } =>_list);
+ }
+ } =>_list);
+}
diff --git a/pkg/compiler/test/kernel/goldens_test.dart b/pkg/compiler/test/kernel/goldens_test.dart
new file mode 100644
index 0000000..a945729
--- /dev/null
+++ b/pkg/compiler/test/kernel/goldens_test.dart
@@ -0,0 +1,46 @@
+// 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';
+
+import 'package:kernel/target/targets.dart';
+import 'package:kernel/ast.dart';
+import 'package:kernel/kernel.dart';
+import 'package:test/test.dart';
+
+import 'common_test_utils.dart';
+
+final String testRootDir = Platform.script.resolve('.').toFilePath();
+
+runTestCase(
+ Uri source, List<String> experimentalFlags, bool enableNullSafety) async {
+ final target =
+ TestingDart2jsTarget(TargetFlags(enableNullSafety: enableNullSafety));
+ Component component = await compileTestCaseToKernelProgram(source,
+ target: target, experimentalFlags: experimentalFlags);
+
+ String actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
+
+ compareResultWithExpectationsFile(source, actual);
+}
+
+main() {
+ group('goldens', () {
+ final testCasesDir = new Directory(testRootDir + '/data');
+
+ for (var entry
+ in testCasesDir.listSync(recursive: true, followLinks: false)) {
+ final path = entry.path;
+ if (path.endsWith('.dart')) {
+ final bool enableNullSafety = path.endsWith('_nnbd_strong.dart');
+ final bool enableNNBD = enableNullSafety || path.endsWith('_nnbd.dart');
+ final List<String> experimentalFlags = [
+ if (enableNNBD) 'non-nullable',
+ ];
+ test(path,
+ () => runTestCase(entry.uri, experimentalFlags, enableNullSafety));
+ }
+ }
+ }, timeout: Timeout.none);
+}
diff --git a/pkg/dartdev/lib/src/commands/test.dart b/pkg/dartdev/lib/src/commands/test.dart
index b4fe29c..2e34c97 100644
--- a/pkg/dartdev/lib/src/commands/test.dart
+++ b/pkg/dartdev/lib/src/commands/test.dart
@@ -5,10 +5,9 @@
import 'dart:async';
import 'package:args/args.dart';
+import 'package:pub/pub.dart';
import '../core.dart';
-import '../experiments.dart';
-import '../sdk.dart';
import '../vm_interop_handler.dart';
/// Implement `dart test`.
@@ -19,110 +18,38 @@
TestCommand() : super(cmdName, 'Run tests in this package.');
+ // This argument parser is here solely to ensure that VM specific flags are
+ // provided before any command and to provide a more consistent help message
+ // with the rest of the tool.
@override
- final ArgParser argParser = ArgParser.allowAnything();
-
- @override
- void printUsage() {
- _runImpl(['-h']);
+ ArgParser createArgParser() {
+ return ArgParser.allowAnything();
}
@override
FutureOr<int> run() async {
- return _runImpl(argResults.arguments.toList());
- }
-
- int _runImpl(List<String> testArgs) {
- if (!Sdk.checkArtifactExists(sdk.pubSnapshot)) {
- return 255;
+ if (argResults.rest.contains('-h') || argResults.rest.contains('--help')) {
+ printUsage();
+ return 0;
}
-
- final pubSnapshot = sdk.pubSnapshot;
-
- bool isHelpCommand = testArgs.contains('--help') || testArgs.contains('-h');
-
- // Check for no pubspec.yaml file.
if (!project.hasPubspecFile) {
- _printNoPubspecMessage(isHelpCommand);
- return 65;
- }
-
- // Handle the case of no .dart_tool/package_config.json file.
- if (!project.hasPackageConfigFile) {
- _printRunPubGetInstructions(isHelpCommand);
- return 65;
- }
-
- // "Could not find package "test". Did you forget to add a dependency?"
- if (!project.packageConfig.hasDependency('test')) {
- _printMissingDepInstructions(isHelpCommand);
- return 65;
- }
- List<String> enabledExperiments = [];
- if (!(testArgs.length == 1 && testArgs[0] == '-h')) {
- enabledExperiments = argResults.enabledExperiments;
- }
- final args = [
- 'run',
- if (enabledExperiments.isNotEmpty)
- '--$experimentFlagName=${enabledExperiments.join(',')}',
- 'test',
- ...testArgs,
- ];
-
- log.trace('$pubSnapshot ${args.join(' ')}');
- VmInteropHandler.run(pubSnapshot, args);
- return 0;
- }
-
- void _printNoPubspecMessage(bool wasHelpCommand) {
- log.stdout('''
+ log.stdout('''
No pubspec.yaml file found; please run this command from the root of your project.
''');
- if (wasHelpCommand) {
- log.stdout(_terseHelp);
- log.stdout('');
+ printUsage();
+ return 65;
}
-
- log.stdout(_usageHelp);
- }
-
- void _printRunPubGetInstructions(bool wasHelpCommand) {
- log.stdout('''
-No .dart_tool/package_config.json file found, please run 'dart pub get'.
-''');
-
- if (wasHelpCommand) {
- log.stdout(_terseHelp);
- log.stdout('');
+ try {
+ final testExecutable = await getExecutableForCommand('test:test');
+ log.trace('dart $testExecutable ${argResults.rest.join(' ')}');
+ VmInteropHandler.run(testExecutable, argResults.rest);
+ return 0;
+ } on CommandResolutionFailedException catch (e) {
+ print(e.message);
+ print('You need to add a dependency on package:test.');
+ print('Try running `dart pub add test`.');
+ return 65;
}
-
- log.stdout(_usageHelp);
- }
-
- void _printMissingDepInstructions(bool wasHelpCommand) {
- final ansi = log.ansi;
-
- log.stdout('''
-No dependency on package:test found. In order to run tests, you need to add a dependency
-on package:test in your pubspec.yaml file:
-
-${ansi.emphasized('dev_dependencies:\n test: ^1.0.0')}
-
-See https://pub.dev/packages/test/install for more information on adding package:test,
-and https://dart.dev/guides/testing for general information on testing.
-''');
-
- if (wasHelpCommand) {
- log.stdout(_terseHelp);
- log.stdout('');
- }
-
- log.stdout(_usageHelp);
}
}
-
-const String _terseHelp = 'Run tests in this package.';
-
-const String _usageHelp = 'Usage: dart test [files or directories...]';
diff --git a/pkg/dartdev/test/commands/test_test.dart b/pkg/dartdev/test/commands/test_test.dart
index cf7aea9..ff85982 100644
--- a/pkg/dartdev/test/commands/test_test.dart
+++ b/pkg/dartdev/test/commands/test_test.dart
@@ -21,10 +21,7 @@
test('--help', () {
p = project();
- var result = p.runSync('pub', ['get']);
- expect(result.exitCode, 0);
-
- result = p.runSync('test', ['--help']);
+ final result = p.runSync('test', ['--help']);
expect(result.exitCode, 0);
expect(result.stdout, contains(' tests in this package'));
@@ -34,10 +31,7 @@
test('dart help test', () {
p = project();
- var result = p.runSync('pub', ['get']);
- expect(result.exitCode, 0);
-
- result = p.runSync('help', ['test']);
+ final result = p.runSync('help', ['test']);
expect(result.exitCode, 0);
expect(result.stdout, contains(' tests in this package'));
@@ -49,22 +43,30 @@
var pubspec = File(path.join(p.dirPath, 'pubspec.yaml'));
pubspec.deleteSync();
- var result = p.runSync('help', ['test']);
+ var result = p.runSync('test', []);
- expect(result.exitCode, 0);
- expect(result.stdout, contains('No pubspec.yaml file found'));
expect(result.stderr, isEmpty);
+ expect(result.stdout, contains('No pubspec.yaml file found'));
+ expect(result.exitCode, 65);
});
- test('no .dart_tool/package_config.json', () {
+ test('runs test', () {
p = project();
+ p.file('test/foo_test.dart', '''
+import 'package:test/test.dart';
- var result = p.runSync('help', ['test']);
+void main() {
+ test('', () {
+ expect(1,1);
+ });
+}
+''');
- expect(result.exitCode, 0);
- expect(result.stdout,
- contains('No .dart_tool/package_config.json file found'));
+ // An implicit `pub get` will happen.
+ final result = p.runSync('test', ['--no-color', '--reporter', 'expanded']);
expect(result.stderr, isEmpty);
+ expect(result.stdout, contains('All tests passed!'));
+ expect(result.exitCode, 0);
});
test('no package:test dependency', () {
@@ -74,16 +76,31 @@
environment:
sdk: '>=2.10.0 <3.0.0'
''');
+ p.file('test/foo_test.dart', '''
+import 'package:test/test.dart';
- var result = p.runSync('pub', ['get']);
- expect(result.exitCode, 0);
+void main() {
+ test('', () {
+ expect(1,1);
+ });
+}
+''');
- result = p.runSync('test', []);
- expect(result.exitCode, 65);
+ final result = p.runSync('test', []);
expect(
result.stdout,
- contains('In order to run tests, you need to add a dependency'),
+ contains('You need to add a dependency on package:test'),
);
+ expect(result.stderr, isEmpty);
+ expect(result.exitCode, 65);
+
+ final resultPubAdd = p.runSync('pub', ['add', 'test']);
+
+ expect(resultPubAdd.exitCode, 0);
+ final result2 = p.runSync('test', ['--no-color', '--reporter', 'expanded']);
+ expect(result2.stderr, isEmpty);
+ expect(result2.stdout, contains('All tests passed!'));
+ expect(result2.exitCode, 0);
});
test('has package:test dependency', () {
@@ -100,10 +117,7 @@
}
''');
- var result = p.runSync('pub', ['get']);
- expect(result.exitCode, 0);
-
- result = p.runSync('test', ['--no-color', '--reporter', 'expanded']);
+ final result = p.runSync('test', ['--no-color', '--reporter', 'expanded']);
expect(result.exitCode, 0);
expect(result.stdout, contains('All tests passed!'));
expect(result.stderr, isEmpty);
@@ -123,11 +137,10 @@
}
''');
- var result = p.runSync('pub', ['get']);
- expect(result.exitCode, 0);
-
- result = p.runSync('--enable-experiment=non-nullable',
- ['test', '--no-color', '--reporter', 'expanded']);
+ final result = p.runSync(
+ '--enable-experiment=non-nullable',
+ ['test', '--no-color', '--reporter', 'expanded'],
+ );
expect(result.exitCode, 1);
});
}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 16cd2fe..371f472 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2639,6 +2639,7 @@
{bool emitNullability = true}) {
var c = type.classNode;
_declareBeforeUse(c);
+ js_ast.Expression typeRep;
// Type parameters don't matter as JS interop types cannot be reified.
// We have to use lazy JS types because until we have proper module
@@ -2654,17 +2655,25 @@
// Anonymous JS types do not have a corresponding concrete JS type so we
// have to use a helper to define them.
if (isJSAnonymousType(c)) {
- return runtimeCall(
+ typeRep = runtimeCall(
'anonymousJSType(#)', [js.escapedString(getLocalClassName(c))]);
+ } else {
+ var jsName = _jsNameWithoutGlobal(c);
+ if (jsName != null) {
+ typeRep = runtimeCall('lazyJSType(() => #, #)',
+ [_emitJSInteropForGlobal(jsName), js.escapedString(jsName)]);
+ }
}
- var jsName = _jsNameWithoutGlobal(c);
- if (jsName != null) {
- return runtimeCall('lazyJSType(() => #, #)',
- [_emitJSInteropForGlobal(jsName), js.escapedString(jsName)]);
+
+ if (typeRep != null) {
+ // JS types are not currently cached in the type table like other types
+ // are below.
+ return emitNullability
+ ? _emitNullabilityWrapper(typeRep, type.nullability)
+ : typeRep;
}
var args = type.typeArguments;
- js_ast.Expression typeRep;
Iterable<js_ast.Expression> jsArgs;
if (args.any((a) => a != const DynamicType())) {
jsArgs = args.map(_emitType);
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index f389110..eb2f225 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -34,7 +34,7 @@
bool get enableSuperMixins => true;
@override
- bool get supportsLateFields => false;
+ int get enabledLateLowerings => LateLowering.all;
@override
bool get supportsLateLoweringSentinel => false;
diff --git a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
index bf80618..d85029a 100644
--- a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
@@ -1,12 +1,12 @@
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '&': JSNumber.& (num Function(num)), int.& (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '<<': JSNumber.<< (num Function(num)), int.<< (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1659|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1514|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
-ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1516|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1676|28|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1678|27|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1681|17|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1686|18|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1686|44|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '&': JSNumber.& (num Function(num)), int.& (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '<<': JSNumber.<< (num Function(num)), int.<< (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1706|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1561|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
+ERROR|COMPILE_TIME_ERROR|RETURN_OF_INVALID_TYPE|lib/_internal/js_runtime/lib/interceptors.dart|1563|14|45|A value of type 'double' can't be returned from method '%' because it has a return type of 'JSNumber'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1723|28|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1725|27|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1728|17|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1733|18|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1733|44|1|The operator '&' isn't defined for the type 'JSInt'.
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index a030354..3b7a2e5 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -618,19 +618,6 @@
f, (error) => error.toString().startsWith('ReachabilityError'), reason);
}
- /// Checks that [f] throws an appropriate error on a null argument.
- ///
- /// With sound null safety, this is expected to be a [TypeError] when casting
- /// the `null` to some non-nullable type. In weak mode, that cast is ignored
- /// and some later explicit validation should handle it and [ArgumentError].
- static void throwsNullCheckError(void f()) {
- if (hasSoundNullSafety) {
- throwsTypeError(f);
- } else {
- throwsArgumentError(f);
- }
- }
-
static void throwsRangeError(void f(), [String reason = "RangeError"]) {
Expect.throws(f, (error) => error is RangeError, reason);
}
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 63f82eb..658e1d0 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -136,7 +136,10 @@
isCovariant: isCovariant,
isNonNullableByDefault: library.isNonNullableByDefault);
} else if (isLate &&
- !libraryBuilder.loader.target.backendTarget.supportsLateFields) {
+ libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled(
+ hasInitializer: hasInitializer,
+ isFinal: isFinal,
+ isStatic: (isStatic || isTopLevel))) {
if (hasInitializer) {
if (isFinal) {
_fieldEncoding = new LateFinalFieldWithInitializerEncoding(
@@ -229,6 +232,8 @@
}
}
+ bool get isLateLowered => _fieldEncoding.isLateLowering;
+
bool _typeEnsured = false;
Set<ClassMember> _overrideDependencies;
@@ -570,6 +575,9 @@
/// Ensures that the signatures all members created by this field encoding
/// are fully typed.
void completeSignature(CoreTypes coreTypes);
+
+ /// Returns `true` if this encoding is a late lowering.
+ bool get isLateLowering;
}
class RegularFieldEncoding implements FieldEncoding {
@@ -695,6 +703,9 @@
fieldBuilder.isAssignable
? <ClassMember>[new SourceFieldMember(fieldBuilder, forSetter: true)]
: const <ClassMember>[];
+
+ @override
+ bool get isLateLowering => false;
}
class SourceFieldMember extends BuilderClassMember {
@@ -1146,6 +1157,9 @@
}
return list;
}
+
+ @override
+ bool get isLateLowering => true;
}
mixin NonFinalLate on AbstractLateFieldEncoding {
@@ -1684,6 +1698,9 @@
forSetter: true, isInternalImplementation: false)
]
: const <ClassMember>[];
+
+ @override
+ bool get isLateLowering => false;
}
enum _SynthesizedFieldMemberKind {
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 f64bdf2..2b8458e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -5886,7 +5886,10 @@
}
}
if (node.isLate &&
- !inferrer.library.loader.target.backendTarget.supportsLateFields) {
+ inferrer.library.loader.target.backendTarget.isLateLocalLoweringEnabled(
+ hasInitializer: node.hasDeclaredInitializer,
+ isFinal: node.isFinal,
+ isPotentiallyNullable: node.type.isPotentiallyNullable)) {
int fileOffset = node.fileOffset;
List<Statement> result = <Statement>[];
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 a1167d5..4cd7a7e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1184,8 +1184,8 @@
name,
isInstanceMember: fieldBuilder.isClassInstanceMember,
className: builder.name,
- isSynthesized: fieldBuilder.isLate &&
- !builder.library.loader.target.backendTarget.supportsLateFields,
+ isSynthesized:
+ fieldBuilder is SourceFieldBuilder && fieldBuilder.isLateLowered,
));
});
builder.forEach((String name, Builder builder) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index e4d81e4..54f31d9 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -2119,7 +2119,10 @@
Procedure getterReferenceFrom;
Procedure setterReferenceFrom;
final bool fieldIsLateWithLowering = (modifiers & lateMask) != 0 &&
- !loader.target.backendTarget.supportsLateFields;
+ loader.target.backendTarget.isLateFieldLoweringEnabled(
+ hasInitializer: hasInitializer,
+ isFinal: (modifiers & finalMask) != 0,
+ isStatic: isTopLevel || (modifiers & staticMask) != 0);
final bool isInstanceMember = currentTypeParameterScopeBuilder.kind ==
TypeParameterScopeKind.classDeclaration &&
(modifiers & staticMask) == 0;
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index c9d68e8..3788cba 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -105,6 +105,7 @@
DiagnosticReporter,
NoneConstantsBackend,
NoneTarget,
+ LateLowering,
Target,
TargetFlags;
@@ -205,7 +206,7 @@
/// test folders.
class FolderOptions {
final Map<ExperimentalFlag, bool> _explicitExperimentalFlags;
- final bool forceLateLowering;
+ final int forceLateLowerings;
final bool forceLateLoweringSentinel;
final bool forceStaticFieldLowering;
final bool forceNoExplicitGetterCalls;
@@ -216,7 +217,7 @@
final String overwriteCurrentSdkVersion;
FolderOptions(this._explicitExperimentalFlags,
- {this.forceLateLowering: false,
+ {this.forceLateLowerings: LateLowering.none,
this.forceLateLoweringSentinel: false,
this.forceStaticFieldLowering: false,
this.forceNoExplicitGetterCalls: false,
@@ -226,7 +227,7 @@
this.target: "vm",
// can be null
this.overwriteCurrentSdkVersion})
- : assert(forceLateLowering != null),
+ : assert(forceLateLowerings != null),
assert(forceLateLoweringSentinel != null),
assert(forceStaticFieldLowering != null),
assert(forceNoExplicitGetterCalls != null),
@@ -376,7 +377,7 @@
FolderOptions _computeFolderOptions(Directory directory) {
FolderOptions folderOptions = _folderOptions[directory.uri];
if (folderOptions == null) {
- bool forceLateLowering = false;
+ int forceLateLowering = LateLowering.none;
bool forceLateLoweringSentinel = false;
bool forceStaticFieldLowering = false;
bool forceNoExplicitGetterCalls = false;
@@ -386,7 +387,7 @@
String target = "vm";
if (directory.uri == baseUri) {
folderOptions = new FolderOptions({},
- forceLateLowering: forceLateLowering,
+ forceLateLowerings: forceLateLowering,
forceLateLoweringSentinel: forceLateLoweringSentinel,
forceStaticFieldLowering: forceStaticFieldLowering,
forceNoExplicitGetterCalls: forceNoExplicitGetterCalls,
@@ -410,8 +411,12 @@
line.substring(overwriteCurrentSdkVersion.length);
} else if (line.startsWith(Flags.forceLateLoweringSentinel)) {
forceLateLoweringSentinel = true;
+ } else if (line.startsWith('${Flags.forceLateLowering}=')) {
+ int mask = int.parse(
+ line.substring('${Flags.forceLateLowering}='.length));
+ forceLateLowering = mask;
} else if (line.startsWith(Flags.forceLateLowering)) {
- forceLateLowering = true;
+ forceLateLowering = LateLowering.all;
} else if (line.startsWith(Flags.forceStaticFieldLowering)) {
forceStaticFieldLowering = true;
} else if (line.startsWith(Flags.forceNoExplicitGetterCalls)) {
@@ -466,7 +471,7 @@
onError: (String message) => throw new ArgumentError(message),
onWarning: (String message) =>
throw new ArgumentError(message)),
- forceLateLowering: forceLateLowering,
+ forceLateLowerings: forceLateLowering,
forceLateLoweringSentinel: forceLateLoweringSentinel,
forceStaticFieldLowering: forceStaticFieldLowering,
forceNoExplicitGetterCalls: forceNoExplicitGetterCalls,
@@ -743,7 +748,7 @@
StdioProcess process;
try {
var args = <String>[];
- if (experimentalFlags[ExperimentalFlag.nonNullable]) {
+ if (experimentalFlags[ExperimentalFlag.nonNullable] == true) {
args.add("--enable-experiment=non-nullable");
if (!context.weak) {
args.add("--sound-null-safety");
@@ -1134,7 +1139,7 @@
UriTranslator uriTranslator =
await context.computeUriTranslator(description);
TargetFlags targetFlags = new TargetFlags(
- forceLateLoweringForTesting: testOptions.forceLateLowering,
+ forceLateLoweringsForTesting: testOptions.forceLateLowerings,
forceLateLoweringSentinelForTesting:
testOptions.forceLateLoweringSentinel,
forceStaticFieldLoweringForTesting: testOptions.forceStaticFieldLowering,
diff --git a/pkg/front_end/test/incremental_load_from_dill_suite.dart b/pkg/front_end/test/incremental_load_from_dill_suite.dart
index a6237db..45cc440 100644
--- a/pkg/front_end/test/incremental_load_from_dill_suite.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_suite.dart
@@ -68,7 +68,7 @@
Version;
import 'package:kernel/target/targets.dart'
- show NoneTarget, Target, TargetFlags;
+ show NoneTarget, LateLowering, Target, TargetFlags;
import 'package:kernel/text/ast_to_text.dart' show Printer, componentToString;
@@ -392,7 +392,8 @@
final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
TargetFlags targetFlags = new TargetFlags(
- forceLateLoweringForTesting: forceLateLoweringForTesting,
+ forceLateLoweringsForTesting:
+ forceLateLoweringForTesting ? LateLowering.all : LateLowering.none,
trackWidgetCreation: trackWidgetCreation);
Target target = new VmTarget(targetFlags);
String sdkSummary = "vm_platform_strong.dill";
diff --git a/pkg/front_end/test/lint_test.status b/pkg/front_end/test/lint_test.status
index 10f7b68..2728954 100644
--- a/pkg/front_end/test/lint_test.status
+++ b/pkg/front_end/test/lint_test.status
@@ -39,3 +39,8 @@
front_end/lib/src/fasta/type_inference/type_constraint_gatherer/ImportsTwice: Fail
front_end/lib/src/fasta/type_inference/type_inferrer/ImportsTwice: Fail
front_end/lib/src/testing/id_testing_helper/Exports: Fail
+kernel/lib/ast/ImportsTwice: Fail
+kernel/lib/ast/Exports: Fail
+kernel/lib/kernel/Exports: Fail
+kernel/lib/testing/type_parser_environment/ImportsTwice: Fail
+kernel/lib/text/ast_to_text/ImportsTwice: Fail
diff --git a/pkg/front_end/test/predicates/predicate_test.dart b/pkg/front_end/test/predicates/predicate_test.dart
index 89ddb9f..d2143dd 100644
--- a/pkg/front_end/test/predicates/predicate_test.dart
+++ b/pkg/front_end/test/predicates/predicate_test.dart
@@ -25,7 +25,8 @@
explicitExperimentalFlags: const {
ExperimentalFlag.nonNullable: true
},
- targetFlags: const TargetFlags(forceLateLoweringForTesting: true))
+ targetFlags: const TargetFlags(
+ forceLateLoweringsForTesting: LateLowering.all))
]));
}
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index d50f907..204181e 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -55,6 +55,7 @@
besides
beta
bigger
+bitmask
bkonyi
bla
blah
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.1.expect
index 994228a..3749032 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.1.expect
@@ -479,7 +479,7 @@
return 1.{dart.core::int::unary-}();
}
method /*isNonNullableByDefault, from org-dartlang-sdk:///sdk/lib/collection/list.dart */ insert(dart.core::int index, generic-covariant-impl dart.core::int* element) → void {
- dart.core::ArgumentError::checkNotNull<dart.core::int>(index, "index");
+ dart._internal::checkNotNullable<dart.core::int>(index, "index");
dart.core::int length = this.{dart.core::List::length};
dart.core::RangeError::checkValueInInterval(index, 0, length, "index");
this.{dart.collection::ListMixin::add}(element);
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.2.expect
index 994228a..3749032 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_22.yaml.world.2.expect
@@ -479,7 +479,7 @@
return 1.{dart.core::int::unary-}();
}
method /*isNonNullableByDefault, from org-dartlang-sdk:///sdk/lib/collection/list.dart */ insert(dart.core::int index, generic-covariant-impl dart.core::int* element) → void {
- dart.core::ArgumentError::checkNotNull<dart.core::int>(index, "index");
+ dart._internal::checkNotNullable<dart.core::int>(index, "index");
dart.core::int length = this.{dart.core::List::length};
dart.core::RangeError::checkValueInInterval(index, 0, length, "index");
this.{dart.collection::ListMixin::add}(element);
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart
new file mode 100644
index 0000000..b5a6079
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart
@@ -0,0 +1,36 @@
+// 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.
+
+// A declaration for each kind of late field/local lowering enabled by
+// target bitmask.
+
+main() {}
+
+method() {
+ late int? nullableUninitializedNonFinalLocal;
+ late int nonNullableUninitializedNonFinalLocal;
+ late final int? nullableUninitializedFinalLocal;
+ late final int nonNullableUninitializedFinalLocal;
+ late int? nullableInitializedNonFinalLocal = 0;
+ late int nonNullableInitializedNonFinalLocal = 0;
+ late final int? nullableInitializedFinalLocal = 0;
+ late final int nonNullableInitializedFinalLocal = 0;
+}
+
+late int uninitializedNonFinalTopLevelField;
+late final int uninitializedFinalTopLevelField;
+late int initializedNonFinalTopLevelField = 0;
+late final int initializedFinalTopLevelField = 0;
+
+class Class {
+ static late int uninitializedNonFinalStaticField;
+ static late final int uninitializedFinalStaticField;
+ static late int initializedNonFinalStaticField = 0;
+ static late final int initializedFinalStaticField = 0;
+
+ late int uninitializedNonFinalInstanceField;
+ late final int uninitializedFinalInstanceField;
+ late int initializedNonFinalInstanceField = 0;
+ late final int initializedFinalInstanceField = 0;
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.outline.expect
new file mode 100644
index 0000000..9c49adf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.outline.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField;
+ static field core::int? _#uninitializedFinalStaticField;
+ static field core::int? _#initializedNonFinalStaticField;
+ static field core::int? _#initializedFinalStaticField;
+ field core::int? _#Class#uninitializedNonFinalInstanceField;
+ field core::int? _#Class#uninitializedFinalInstanceField;
+ field core::int? _#Class#initializedNonFinalInstanceField;
+ field core::int? _#Class#initializedFinalInstanceField;
+ synthetic constructor •() → self::Class
+ ;
+ static get uninitializedNonFinalStaticField() → core::int;
+ static set uninitializedNonFinalStaticField(core::int #t1) → void;
+ static get uninitializedFinalStaticField() → core::int;
+ static set uninitializedFinalStaticField(core::int #t2) → void;
+ static get initializedNonFinalStaticField() → core::int;
+ static set initializedNonFinalStaticField(core::int #t3) → void;
+ static get initializedFinalStaticField() → core::int;
+ get uninitializedNonFinalInstanceField() → core::int;
+ set uninitializedNonFinalInstanceField(core::int #t4) → void;
+ get uninitializedFinalInstanceField() → core::int;
+ set uninitializedFinalInstanceField(core::int #t5) → void;
+ get initializedNonFinalInstanceField() → core::int;
+ set initializedNonFinalInstanceField(core::int #t6) → void;
+ get initializedFinalInstanceField() → core::int;
+}
+static field core::int? _#uninitializedNonFinalTopLevelField;
+static field core::int? _#uninitializedFinalTopLevelField;
+static field core::int? _#initializedNonFinalTopLevelField;
+static field core::int? _#initializedFinalTopLevelField;
+static method main() → dynamic
+ ;
+static method method() → dynamic
+ ;
+static get uninitializedNonFinalTopLevelField() → core::int;
+static set uninitializedNonFinalTopLevelField(core::int #t7) → void;
+static get uninitializedFinalTopLevelField() → core::int;
+static set uninitializedFinalTopLevelField(core::int #t8) → void;
+static get initializedNonFinalTopLevelField() → core::int;
+static set initializedNonFinalTopLevelField(core::int #t9) → void;
+static get initializedFinalTopLevelField() → core::int;
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.strong.expect
new file mode 100644
index 0000000..b67f124
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.strong.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::int? _#initializedFinalStaticField = null;
+ field core::int? _#Class#uninitializedNonFinalInstanceField = null;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField") : #t1{core::int};
+ static set uninitializedNonFinalStaticField(core::int #t2) → void
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ static get uninitializedFinalStaticField() → core::int
+ return let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalStaticField") : #t3{core::int};
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField.==(null))
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ static get initializedNonFinalStaticField() → core::int
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5.==(null) ?{core::int} self::Class::_#initializedNonFinalStaticField = 0 : #t5{core::int};
+ static set initializedNonFinalStaticField(core::int #t6) → void
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ static get initializedFinalStaticField() → core::int
+ return let final core::int? #t7 = self::Class::_#initializedFinalStaticField in #t7.==(null) ?{core::int} let final core::int #t8 = 0 in self::Class::_#initializedFinalStaticField.==(null) ?{core::int} self::Class::_#initializedFinalStaticField = #t8 : throw new _in::LateError::fieldADI("initializedFinalStaticField") : #t7{core::int};
+ get uninitializedNonFinalInstanceField() → core::int
+ return let final core::int? #t9 = this.{self::Class::_#Class#uninitializedNonFinalInstanceField} in #t9.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalInstanceField") : #t9{core::int};
+ set uninitializedNonFinalInstanceField(core::int #t10) → void
+ this.{self::Class::_#Class#uninitializedNonFinalInstanceField} = #t10;
+ get uninitializedFinalInstanceField() → core::int
+ return let final core::int? #t11 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t11.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalInstanceField") : #t11{core::int};
+ set uninitializedFinalInstanceField(core::int #t12) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField}.==(null))
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t12;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ get initializedNonFinalInstanceField() → core::int
+ return let final core::int? #t13 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t13.==(null) ?{core::int} this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0 : #t13{core::int};
+ set initializedNonFinalInstanceField(core::int #t14) → void
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t14;
+ get initializedFinalInstanceField() → core::int
+ return let final core::int? #t15 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::Class::_#Class#initializedFinalInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#initializedFinalInstanceField} = #t16 : throw new _in::LateError::fieldADI("initializedFinalInstanceField") : #t15{core::int};
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::int? _#initializedFinalTopLevelField = null;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t17) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t17;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t18 = nonNullableUninitializedNonFinalLocal in #t18.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal") : #t18{core::int};
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t19) → dynamic
+ return nonNullableUninitializedNonFinalLocal = #t19;
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t20) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t20;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return let final core::int? #t21 = nonNullableUninitializedFinalLocal in #t21.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal") : #t21{core::int};
+ function #nonNullableUninitializedFinalLocal#set(core::int #t22) → dynamic
+ if(nonNullableUninitializedFinalLocal.==(null))
+ return nonNullableUninitializedFinalLocal = #t22;
+ else
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t23) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t23;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t24 = nonNullableInitializedNonFinalLocal in #t24.==(null) ?{core::int} nonNullableInitializedNonFinalLocal = 0 : #t24{core::int};
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t25) → dynamic
+ return nonNullableInitializedNonFinalLocal = #t25;
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ function #nonNullableInitializedFinalLocal#get() → core::int
+ return let final core::int? #t26 = nonNullableInitializedFinalLocal in #t26.==(null) ?{core::int} nonNullableInitializedFinalLocal = 0 : #t26{core::int};
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t27 = self::_#uninitializedNonFinalTopLevelField in #t27.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField") : #t27{core::int};
+static set uninitializedNonFinalTopLevelField(core::int #t28) → void
+ self::_#uninitializedNonFinalTopLevelField = #t28;
+static get uninitializedFinalTopLevelField() → core::int
+ return let final core::int? #t29 = self::_#uninitializedFinalTopLevelField in #t29.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField") : #t29{core::int};
+static set uninitializedFinalTopLevelField(core::int #t30) → void
+ if(self::_#uninitializedFinalTopLevelField.==(null))
+ self::_#uninitializedFinalTopLevelField = #t30;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+static get initializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t31 = self::_#initializedNonFinalTopLevelField in #t31.==(null) ?{core::int} self::_#initializedNonFinalTopLevelField = 0 : #t31{core::int};
+static set initializedNonFinalTopLevelField(core::int #t32) → void
+ self::_#initializedNonFinalTopLevelField = #t32;
+static get initializedFinalTopLevelField() → core::int
+ return let final core::int? #t33 = self::_#initializedFinalTopLevelField in #t33.==(null) ?{core::int} let final core::int #t34 = 0 in self::_#initializedFinalTopLevelField.==(null) ?{core::int} self::_#initializedFinalTopLevelField = #t34 : throw new _in::LateError::fieldADI("initializedFinalTopLevelField") : #t33{core::int};
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.strong.transformed.expect
new file mode 100644
index 0000000..b3a9855
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.strong.transformed.expect
@@ -0,0 +1,145 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::int? _#initializedFinalStaticField = null;
+ field core::int? _#Class#uninitializedNonFinalInstanceField = null;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField") : #t1{core::int};
+ static set uninitializedNonFinalStaticField(core::int #t2) → void
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ static get uninitializedFinalStaticField() → core::int
+ return let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalStaticField") : #t3{core::int};
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField.==(null))
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ static get initializedNonFinalStaticField() → core::int
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5.==(null) ?{core::int} self::Class::_#initializedNonFinalStaticField = 0 : #t5{core::int};
+ static set initializedNonFinalStaticField(core::int #t6) → void
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ static get initializedFinalStaticField() → core::int
+ return let final core::int? #t7 = self::Class::_#initializedFinalStaticField in #t7.==(null) ?{core::int} let final core::int #t8 = 0 in self::Class::_#initializedFinalStaticField.==(null) ?{core::int} self::Class::_#initializedFinalStaticField = #t8 : throw new _in::LateError::fieldADI("initializedFinalStaticField") : #t7{core::int};
+ get uninitializedNonFinalInstanceField() → core::int
+ return let final core::int? #t9 = this.{self::Class::_#Class#uninitializedNonFinalInstanceField} in #t9.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalInstanceField") : #t9{core::int};
+ set uninitializedNonFinalInstanceField(core::int #t10) → void
+ this.{self::Class::_#Class#uninitializedNonFinalInstanceField} = #t10;
+ get uninitializedFinalInstanceField() → core::int
+ return let final core::int? #t11 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t11.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalInstanceField") : #t11{core::int};
+ set uninitializedFinalInstanceField(core::int #t12) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField}.==(null))
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t12;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ get initializedNonFinalInstanceField() → core::int
+ return let final core::int? #t13 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t13.==(null) ?{core::int} this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0 : #t13{core::int};
+ set initializedNonFinalInstanceField(core::int #t14) → void
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t14;
+ get initializedFinalInstanceField() → core::int
+ return let final core::int? #t15 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::Class::_#Class#initializedFinalInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#initializedFinalInstanceField} = #t16 : throw new _in::LateError::fieldADI("initializedFinalInstanceField") : #t15{core::int};
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::int? _#initializedFinalTopLevelField = null;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t17) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t17;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t18 = nonNullableUninitializedNonFinalLocal in #t18.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal") : #t18{core::int};
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t19) → dynamic
+ return nonNullableUninitializedNonFinalLocal = #t19;
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t20) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t20;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return let final core::int? #t21 = nonNullableUninitializedFinalLocal in #t21.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal") : #t21{core::int};
+ function #nonNullableUninitializedFinalLocal#set(core::int #t22) → dynamic
+ if(nonNullableUninitializedFinalLocal.==(null))
+ return nonNullableUninitializedFinalLocal = #t22;
+ else
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t23) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t23;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t24 = nonNullableInitializedNonFinalLocal in #t24.==(null) ?{core::int} nonNullableInitializedNonFinalLocal = 0 : #t24{core::int};
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t25) → dynamic
+ return nonNullableInitializedNonFinalLocal = #t25;
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ function #nonNullableInitializedFinalLocal#get() → core::int
+ return let final core::int? #t26 = nonNullableInitializedFinalLocal in #t26.==(null) ?{core::int} nonNullableInitializedFinalLocal = 0 : #t26{core::int};
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t27 = self::_#uninitializedNonFinalTopLevelField in #t27.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField") : #t27{core::int};
+static set uninitializedNonFinalTopLevelField(core::int #t28) → void
+ self::_#uninitializedNonFinalTopLevelField = #t28;
+static get uninitializedFinalTopLevelField() → core::int
+ return let final core::int? #t29 = self::_#uninitializedFinalTopLevelField in #t29.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField") : #t29{core::int};
+static set uninitializedFinalTopLevelField(core::int #t30) → void
+ if(self::_#uninitializedFinalTopLevelField.==(null))
+ self::_#uninitializedFinalTopLevelField = #t30;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+static get initializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t31 = self::_#initializedNonFinalTopLevelField in #t31.==(null) ?{core::int} self::_#initializedNonFinalTopLevelField = 0 : #t31{core::int};
+static set initializedNonFinalTopLevelField(core::int #t32) → void
+ self::_#initializedNonFinalTopLevelField = #t32;
+static get initializedFinalTopLevelField() → core::int
+ return let final core::int? #t33 = self::_#initializedFinalTopLevelField in #t33.==(null) ?{core::int} let final core::int #t34 = 0 in self::_#initializedFinalTopLevelField.==(null) ?{core::int} self::_#initializedFinalTopLevelField = #t34 : throw new _in::LateError::fieldADI("initializedFinalTopLevelField") : #t33{core::int};
+
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///late_lowering_bitmasks.dart:30:25 -> IntConstant(0)
+Evaluated: VariableGet @ org-dartlang-testcase:///late_lowering_bitmasks.dart:35:18 -> IntConstant(0)
+Evaluated: VariableGet @ org-dartlang-testcase:///late_lowering_bitmasks.dart:24:16 -> IntConstant(0)
+Extra constant evaluation: evaluated: 224, effectively constant: 3
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.textual_outline.expect
new file mode 100644
index 0000000..83c95c1
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.textual_outline.expect
@@ -0,0 +1,28 @@
+main() {}
+method() {}
+late int ;
+uninitializedNonFinalTopLevelField;
+late ;
+final int uninitializedFinalTopLevelField;
+late int ;
+initializedNonFinalTopLevelField = 0;
+late ;
+final int initializedFinalTopLevelField = 0;
+class Class {
+ static late int ;
+ uninitializedNonFinalStaticField;
+ static late ;
+ final int uninitializedFinalStaticField;
+ static late int ;
+ initializedNonFinalStaticField = 0;
+ static late ;
+ final int initializedFinalStaticField = 0;
+ late int ;
+ uninitializedNonFinalInstanceField;
+ late ;
+ final int uninitializedFinalInstanceField;
+ late int ;
+ initializedNonFinalInstanceField = 0;
+ late ;
+ final int initializedFinalInstanceField = 0;
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.weak.expect
new file mode 100644
index 0000000..0bc36f5
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.weak.expect
@@ -0,0 +1,227 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::bool _#uninitializedNonFinalStaticField#isSet = false;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::bool _#uninitializedFinalStaticField#isSet = false;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::bool _#initializedNonFinalStaticField#isSet = false;
+ static field core::int? _#initializedFinalStaticField = null;
+ static field core::bool _#initializedFinalStaticField#isSet = false;
+ field core::int? _#Class#uninitializedNonFinalInstanceField = null;
+ field core::bool _#Class#uninitializedNonFinalInstanceField#isSet = false;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::bool _#Class#uninitializedFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::bool _#Class#initializedNonFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ field core::bool _#Class#initializedFinalInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return self::Class::_#uninitializedNonFinalStaticField#isSet ?{core::int} let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField");
+ static set uninitializedNonFinalStaticField(core::int #t2) → void {
+ self::Class::_#uninitializedNonFinalStaticField#isSet = true;
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ }
+ static get uninitializedFinalStaticField() → core::int
+ return self::Class::_#uninitializedFinalStaticField#isSet ?{core::int} let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalStaticField");
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ else {
+ self::Class::_#uninitializedFinalStaticField#isSet = true;
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ }
+ static get initializedNonFinalStaticField() → core::int {
+ if(!self::Class::_#initializedNonFinalStaticField#isSet) {
+ self::Class::_#initializedNonFinalStaticField = 0;
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5{core::int};
+ }
+ static set initializedNonFinalStaticField(core::int #t6) → void {
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ }
+ static get initializedFinalStaticField() → core::int {
+ if(!self::Class::_#initializedFinalStaticField#isSet) {
+ final core::int #t7 = 0;
+ if(self::Class::_#initializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalStaticField");
+ self::Class::_#initializedFinalStaticField = #t7;
+ self::Class::_#initializedFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t8 = self::Class::_#initializedFinalStaticField in #t8{core::int};
+ }
+ get uninitializedNonFinalInstanceField() → core::int
+ return this.{self::Class::_#Class#uninitializedNonFinalInstanceField#isSet} ?{core::int} let final core::int? #t9 = this.{self::Class::_#Class#uninitializedNonFinalInstanceField} in #t9{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalInstanceField");
+ set uninitializedNonFinalInstanceField(core::int #t10) → void {
+ this.{self::Class::_#Class#uninitializedNonFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#uninitializedNonFinalInstanceField} = #t10;
+ }
+ get uninitializedFinalInstanceField() → core::int
+ return this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} ?{core::int} let final core::int? #t11 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t11{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalInstanceField");
+ set uninitializedFinalInstanceField(core::int #t12) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ else {
+ this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t12;
+ }
+ get initializedNonFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet}) {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t13 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t13{core::int};
+ }
+ set initializedNonFinalInstanceField(core::int #t14) → void {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t14;
+ }
+ get initializedFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedFinalInstanceField#isSet}) {
+ final core::int #t15 = 0;
+ if(this.{self::Class::_#Class#initializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldADI("initializedFinalInstanceField");
+ this.{self::Class::_#Class#initializedFinalInstanceField} = #t15;
+ this.{self::Class::_#Class#initializedFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t16 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t16{core::int};
+ }
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::bool _#uninitializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::bool _#uninitializedFinalTopLevelField#isSet = false;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::bool _#initializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#initializedFinalTopLevelField = null;
+static field core::bool _#initializedFinalTopLevelField#isSet = false;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t17) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t17;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ core::bool #nonNullableUninitializedNonFinalLocal#isSet = false;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return #nonNullableUninitializedNonFinalLocal#isSet ?{core::int} nonNullableUninitializedNonFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal");
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t18) → dynamic {
+ #nonNullableUninitializedNonFinalLocal#isSet = true;
+ return nonNullableUninitializedNonFinalLocal = #t18;
+ }
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t19) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t19;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ core::bool #nonNullableUninitializedFinalLocal#isSet = false;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return #nonNullableUninitializedFinalLocal#isSet ?{core::int} nonNullableUninitializedFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal");
+ function #nonNullableUninitializedFinalLocal#set(core::int #t20) → dynamic
+ if(#nonNullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ else {
+ #nonNullableUninitializedFinalLocal#isSet = true;
+ return nonNullableUninitializedFinalLocal = #t20;
+ }
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t21) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t21;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ core::bool #nonNullableInitializedNonFinalLocal#isSet = false;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedNonFinalLocal#isSet) {
+ nonNullableInitializedNonFinalLocal = 0;
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedNonFinalLocal{core::int};
+ }
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t22) → dynamic {
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ return nonNullableInitializedNonFinalLocal = #t22;
+ }
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ core::bool #nonNullableInitializedFinalLocal#isSet = false;
+ function #nonNullableInitializedFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedFinalLocal#isSet) {
+ nonNullableInitializedFinalLocal = 0;
+ #nonNullableInitializedFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedFinalLocal{core::int};
+ }
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return self::_#uninitializedNonFinalTopLevelField#isSet ?{core::int} let final core::int? #t23 = self::_#uninitializedNonFinalTopLevelField in #t23{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField");
+static set uninitializedNonFinalTopLevelField(core::int #t24) → void {
+ self::_#uninitializedNonFinalTopLevelField#isSet = true;
+ self::_#uninitializedNonFinalTopLevelField = #t24;
+}
+static get uninitializedFinalTopLevelField() → core::int
+ return self::_#uninitializedFinalTopLevelField#isSet ?{core::int} let final core::int? #t25 = self::_#uninitializedFinalTopLevelField in #t25{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField");
+static set uninitializedFinalTopLevelField(core::int #t26) → void
+ if(self::_#uninitializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+ else {
+ self::_#uninitializedFinalTopLevelField#isSet = true;
+ self::_#uninitializedFinalTopLevelField = #t26;
+ }
+static get initializedNonFinalTopLevelField() → core::int {
+ if(!self::_#initializedNonFinalTopLevelField#isSet) {
+ self::_#initializedNonFinalTopLevelField = 0;
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t27 = self::_#initializedNonFinalTopLevelField in #t27{core::int};
+}
+static set initializedNonFinalTopLevelField(core::int #t28) → void {
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ self::_#initializedNonFinalTopLevelField = #t28;
+}
+static get initializedFinalTopLevelField() → core::int {
+ if(!self::_#initializedFinalTopLevelField#isSet) {
+ final core::int #t29 = 0;
+ if(self::_#initializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalTopLevelField");
+ self::_#initializedFinalTopLevelField = #t29;
+ self::_#initializedFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t30 = self::_#initializedFinalTopLevelField in #t30{core::int};
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.weak.transformed.expect
new file mode 100644
index 0000000..0bc36f5
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_lowering_bitmasks.dart.weak.transformed.expect
@@ -0,0 +1,227 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::bool _#uninitializedNonFinalStaticField#isSet = false;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::bool _#uninitializedFinalStaticField#isSet = false;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::bool _#initializedNonFinalStaticField#isSet = false;
+ static field core::int? _#initializedFinalStaticField = null;
+ static field core::bool _#initializedFinalStaticField#isSet = false;
+ field core::int? _#Class#uninitializedNonFinalInstanceField = null;
+ field core::bool _#Class#uninitializedNonFinalInstanceField#isSet = false;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::bool _#Class#uninitializedFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::bool _#Class#initializedNonFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ field core::bool _#Class#initializedFinalInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return self::Class::_#uninitializedNonFinalStaticField#isSet ?{core::int} let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField");
+ static set uninitializedNonFinalStaticField(core::int #t2) → void {
+ self::Class::_#uninitializedNonFinalStaticField#isSet = true;
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ }
+ static get uninitializedFinalStaticField() → core::int
+ return self::Class::_#uninitializedFinalStaticField#isSet ?{core::int} let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalStaticField");
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ else {
+ self::Class::_#uninitializedFinalStaticField#isSet = true;
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ }
+ static get initializedNonFinalStaticField() → core::int {
+ if(!self::Class::_#initializedNonFinalStaticField#isSet) {
+ self::Class::_#initializedNonFinalStaticField = 0;
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5{core::int};
+ }
+ static set initializedNonFinalStaticField(core::int #t6) → void {
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ }
+ static get initializedFinalStaticField() → core::int {
+ if(!self::Class::_#initializedFinalStaticField#isSet) {
+ final core::int #t7 = 0;
+ if(self::Class::_#initializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalStaticField");
+ self::Class::_#initializedFinalStaticField = #t7;
+ self::Class::_#initializedFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t8 = self::Class::_#initializedFinalStaticField in #t8{core::int};
+ }
+ get uninitializedNonFinalInstanceField() → core::int
+ return this.{self::Class::_#Class#uninitializedNonFinalInstanceField#isSet} ?{core::int} let final core::int? #t9 = this.{self::Class::_#Class#uninitializedNonFinalInstanceField} in #t9{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalInstanceField");
+ set uninitializedNonFinalInstanceField(core::int #t10) → void {
+ this.{self::Class::_#Class#uninitializedNonFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#uninitializedNonFinalInstanceField} = #t10;
+ }
+ get uninitializedFinalInstanceField() → core::int
+ return this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} ?{core::int} let final core::int? #t11 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t11{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalInstanceField");
+ set uninitializedFinalInstanceField(core::int #t12) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ else {
+ this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t12;
+ }
+ get initializedNonFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet}) {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t13 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t13{core::int};
+ }
+ set initializedNonFinalInstanceField(core::int #t14) → void {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t14;
+ }
+ get initializedFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedFinalInstanceField#isSet}) {
+ final core::int #t15 = 0;
+ if(this.{self::Class::_#Class#initializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldADI("initializedFinalInstanceField");
+ this.{self::Class::_#Class#initializedFinalInstanceField} = #t15;
+ this.{self::Class::_#Class#initializedFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t16 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t16{core::int};
+ }
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::bool _#uninitializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::bool _#uninitializedFinalTopLevelField#isSet = false;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::bool _#initializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#initializedFinalTopLevelField = null;
+static field core::bool _#initializedFinalTopLevelField#isSet = false;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t17) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t17;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ core::bool #nonNullableUninitializedNonFinalLocal#isSet = false;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return #nonNullableUninitializedNonFinalLocal#isSet ?{core::int} nonNullableUninitializedNonFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal");
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t18) → dynamic {
+ #nonNullableUninitializedNonFinalLocal#isSet = true;
+ return nonNullableUninitializedNonFinalLocal = #t18;
+ }
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t19) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t19;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ core::bool #nonNullableUninitializedFinalLocal#isSet = false;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return #nonNullableUninitializedFinalLocal#isSet ?{core::int} nonNullableUninitializedFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal");
+ function #nonNullableUninitializedFinalLocal#set(core::int #t20) → dynamic
+ if(#nonNullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ else {
+ #nonNullableUninitializedFinalLocal#isSet = true;
+ return nonNullableUninitializedFinalLocal = #t20;
+ }
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t21) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t21;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ core::bool #nonNullableInitializedNonFinalLocal#isSet = false;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedNonFinalLocal#isSet) {
+ nonNullableInitializedNonFinalLocal = 0;
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedNonFinalLocal{core::int};
+ }
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t22) → dynamic {
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ return nonNullableInitializedNonFinalLocal = #t22;
+ }
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ core::bool #nonNullableInitializedFinalLocal#isSet = false;
+ function #nonNullableInitializedFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedFinalLocal#isSet) {
+ nonNullableInitializedFinalLocal = 0;
+ #nonNullableInitializedFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedFinalLocal{core::int};
+ }
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return self::_#uninitializedNonFinalTopLevelField#isSet ?{core::int} let final core::int? #t23 = self::_#uninitializedNonFinalTopLevelField in #t23{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField");
+static set uninitializedNonFinalTopLevelField(core::int #t24) → void {
+ self::_#uninitializedNonFinalTopLevelField#isSet = true;
+ self::_#uninitializedNonFinalTopLevelField = #t24;
+}
+static get uninitializedFinalTopLevelField() → core::int
+ return self::_#uninitializedFinalTopLevelField#isSet ?{core::int} let final core::int? #t25 = self::_#uninitializedFinalTopLevelField in #t25{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField");
+static set uninitializedFinalTopLevelField(core::int #t26) → void
+ if(self::_#uninitializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+ else {
+ self::_#uninitializedFinalTopLevelField#isSet = true;
+ self::_#uninitializedFinalTopLevelField = #t26;
+ }
+static get initializedNonFinalTopLevelField() → core::int {
+ if(!self::_#initializedNonFinalTopLevelField#isSet) {
+ self::_#initializedNonFinalTopLevelField = 0;
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t27 = self::_#initializedNonFinalTopLevelField in #t27{core::int};
+}
+static set initializedNonFinalTopLevelField(core::int #t28) → void {
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ self::_#initializedNonFinalTopLevelField = #t28;
+}
+static get initializedFinalTopLevelField() → core::int {
+ if(!self::_#initializedFinalTopLevelField#isSet) {
+ final core::int #t29 = 0;
+ if(self::_#initializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalTopLevelField");
+ self::_#initializedFinalTopLevelField = #t29;
+ self::_#initializedFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t30 = self::_#initializedFinalTopLevelField in #t30{core::int};
+}
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/folder.options b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/folder.options
new file mode 100644
index 0000000..d9c5c2f
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/folder.options
@@ -0,0 +1 @@
+--force-late-lowering=0xEFFF
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart
new file mode 100644
index 0000000..b5a6079
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart
@@ -0,0 +1,36 @@
+// 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.
+
+// A declaration for each kind of late field/local lowering enabled by
+// target bitmask.
+
+main() {}
+
+method() {
+ late int? nullableUninitializedNonFinalLocal;
+ late int nonNullableUninitializedNonFinalLocal;
+ late final int? nullableUninitializedFinalLocal;
+ late final int nonNullableUninitializedFinalLocal;
+ late int? nullableInitializedNonFinalLocal = 0;
+ late int nonNullableInitializedNonFinalLocal = 0;
+ late final int? nullableInitializedFinalLocal = 0;
+ late final int nonNullableInitializedFinalLocal = 0;
+}
+
+late int uninitializedNonFinalTopLevelField;
+late final int uninitializedFinalTopLevelField;
+late int initializedNonFinalTopLevelField = 0;
+late final int initializedFinalTopLevelField = 0;
+
+class Class {
+ static late int uninitializedNonFinalStaticField;
+ static late final int uninitializedFinalStaticField;
+ static late int initializedNonFinalStaticField = 0;
+ static late final int initializedFinalStaticField = 0;
+
+ late int uninitializedNonFinalInstanceField;
+ late final int uninitializedFinalInstanceField;
+ late int initializedNonFinalInstanceField = 0;
+ late final int initializedFinalInstanceField = 0;
+}
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.outline.expect b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.outline.expect
new file mode 100644
index 0000000..b65cd70
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.outline.expect
@@ -0,0 +1,43 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField;
+ static field core::int? _#uninitializedFinalStaticField;
+ static field core::int? _#initializedNonFinalStaticField;
+ static field core::int? _#initializedFinalStaticField;
+ late field core::int uninitializedNonFinalInstanceField;
+ field core::int? _#Class#uninitializedFinalInstanceField;
+ field core::int? _#Class#initializedNonFinalInstanceField;
+ field core::int? _#Class#initializedFinalInstanceField;
+ synthetic constructor •() → self::Class
+ ;
+ static get uninitializedNonFinalStaticField() → core::int;
+ static set uninitializedNonFinalStaticField(core::int #t1) → void;
+ static get uninitializedFinalStaticField() → core::int;
+ static set uninitializedFinalStaticField(core::int #t2) → void;
+ static get initializedNonFinalStaticField() → core::int;
+ static set initializedNonFinalStaticField(core::int #t3) → void;
+ static get initializedFinalStaticField() → core::int;
+ get uninitializedFinalInstanceField() → core::int;
+ set uninitializedFinalInstanceField(core::int #t4) → void;
+ get initializedNonFinalInstanceField() → core::int;
+ set initializedNonFinalInstanceField(core::int #t5) → void;
+ get initializedFinalInstanceField() → core::int;
+}
+static field core::int? _#uninitializedNonFinalTopLevelField;
+static field core::int? _#uninitializedFinalTopLevelField;
+static field core::int? _#initializedNonFinalTopLevelField;
+static field core::int? _#initializedFinalTopLevelField;
+static method main() → dynamic
+ ;
+static method method() → dynamic
+ ;
+static get uninitializedNonFinalTopLevelField() → core::int;
+static set uninitializedNonFinalTopLevelField(core::int #t6) → void;
+static get uninitializedFinalTopLevelField() → core::int;
+static set uninitializedFinalTopLevelField(core::int #t7) → void;
+static get initializedNonFinalTopLevelField() → core::int;
+static set initializedNonFinalTopLevelField(core::int #t8) → void;
+static get initializedFinalTopLevelField() → core::int;
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.strong.expect b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.strong.expect
new file mode 100644
index 0000000..d63b6e3
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.strong.expect
@@ -0,0 +1,134 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::int? _#initializedFinalStaticField = null;
+ late field core::int uninitializedNonFinalInstanceField;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField") : #t1{core::int};
+ static set uninitializedNonFinalStaticField(core::int #t2) → void
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ static get uninitializedFinalStaticField() → core::int
+ return let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalStaticField") : #t3{core::int};
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField.==(null))
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ static get initializedNonFinalStaticField() → core::int
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5.==(null) ?{core::int} self::Class::_#initializedNonFinalStaticField = 0 : #t5{core::int};
+ static set initializedNonFinalStaticField(core::int #t6) → void
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ static get initializedFinalStaticField() → core::int
+ return let final core::int? #t7 = self::Class::_#initializedFinalStaticField in #t7.==(null) ?{core::int} let final core::int #t8 = 0 in self::Class::_#initializedFinalStaticField.==(null) ?{core::int} self::Class::_#initializedFinalStaticField = #t8 : throw new _in::LateError::fieldADI("initializedFinalStaticField") : #t7{core::int};
+ get uninitializedFinalInstanceField() → core::int
+ return let final core::int? #t9 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t9.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalInstanceField") : #t9{core::int};
+ set uninitializedFinalInstanceField(core::int #t10) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField}.==(null))
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t10;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ get initializedNonFinalInstanceField() → core::int
+ return let final core::int? #t11 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t11.==(null) ?{core::int} this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0 : #t11{core::int};
+ set initializedNonFinalInstanceField(core::int #t12) → void
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t12;
+ get initializedFinalInstanceField() → core::int
+ return let final core::int? #t13 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t13.==(null) ?{core::int} let final core::int #t14 = 0 in this.{self::Class::_#Class#initializedFinalInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#initializedFinalInstanceField} = #t14 : throw new _in::LateError::fieldADI("initializedFinalInstanceField") : #t13{core::int};
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::int? _#initializedFinalTopLevelField = null;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t15) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t15;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t16 = nonNullableUninitializedNonFinalLocal in #t16.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal") : #t16{core::int};
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t17) → dynamic
+ return nonNullableUninitializedNonFinalLocal = #t17;
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t18) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t18;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return let final core::int? #t19 = nonNullableUninitializedFinalLocal in #t19.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal") : #t19{core::int};
+ function #nonNullableUninitializedFinalLocal#set(core::int #t20) → dynamic
+ if(nonNullableUninitializedFinalLocal.==(null))
+ return nonNullableUninitializedFinalLocal = #t20;
+ else
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t21) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t21;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t22 = nonNullableInitializedNonFinalLocal in #t22.==(null) ?{core::int} nonNullableInitializedNonFinalLocal = 0 : #t22{core::int};
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t23) → dynamic
+ return nonNullableInitializedNonFinalLocal = #t23;
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ function #nonNullableInitializedFinalLocal#get() → core::int
+ return let final core::int? #t24 = nonNullableInitializedFinalLocal in #t24.==(null) ?{core::int} nonNullableInitializedFinalLocal = 0 : #t24{core::int};
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t25 = self::_#uninitializedNonFinalTopLevelField in #t25.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField") : #t25{core::int};
+static set uninitializedNonFinalTopLevelField(core::int #t26) → void
+ self::_#uninitializedNonFinalTopLevelField = #t26;
+static get uninitializedFinalTopLevelField() → core::int
+ return let final core::int? #t27 = self::_#uninitializedFinalTopLevelField in #t27.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField") : #t27{core::int};
+static set uninitializedFinalTopLevelField(core::int #t28) → void
+ if(self::_#uninitializedFinalTopLevelField.==(null))
+ self::_#uninitializedFinalTopLevelField = #t28;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+static get initializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t29 = self::_#initializedNonFinalTopLevelField in #t29.==(null) ?{core::int} self::_#initializedNonFinalTopLevelField = 0 : #t29{core::int};
+static set initializedNonFinalTopLevelField(core::int #t30) → void
+ self::_#initializedNonFinalTopLevelField = #t30;
+static get initializedFinalTopLevelField() → core::int
+ return let final core::int? #t31 = self::_#initializedFinalTopLevelField in #t31.==(null) ?{core::int} let final core::int #t32 = 0 in self::_#initializedFinalTopLevelField.==(null) ?{core::int} self::_#initializedFinalTopLevelField = #t32 : throw new _in::LateError::fieldADI("initializedFinalTopLevelField") : #t31{core::int};
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..23aeb4d
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.strong.transformed.expect
@@ -0,0 +1,141 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::int? _#initializedFinalStaticField = null;
+ late field core::int uninitializedNonFinalInstanceField;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField") : #t1{core::int};
+ static set uninitializedNonFinalStaticField(core::int #t2) → void
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ static get uninitializedFinalStaticField() → core::int
+ return let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalStaticField") : #t3{core::int};
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField.==(null))
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ static get initializedNonFinalStaticField() → core::int
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5.==(null) ?{core::int} self::Class::_#initializedNonFinalStaticField = 0 : #t5{core::int};
+ static set initializedNonFinalStaticField(core::int #t6) → void
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ static get initializedFinalStaticField() → core::int
+ return let final core::int? #t7 = self::Class::_#initializedFinalStaticField in #t7.==(null) ?{core::int} let final core::int #t8 = 0 in self::Class::_#initializedFinalStaticField.==(null) ?{core::int} self::Class::_#initializedFinalStaticField = #t8 : throw new _in::LateError::fieldADI("initializedFinalStaticField") : #t7{core::int};
+ get uninitializedFinalInstanceField() → core::int
+ return let final core::int? #t9 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t9.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalInstanceField") : #t9{core::int};
+ set uninitializedFinalInstanceField(core::int #t10) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField}.==(null))
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t10;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ get initializedNonFinalInstanceField() → core::int
+ return let final core::int? #t11 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t11.==(null) ?{core::int} this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0 : #t11{core::int};
+ set initializedNonFinalInstanceField(core::int #t12) → void
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t12;
+ get initializedFinalInstanceField() → core::int
+ return let final core::int? #t13 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t13.==(null) ?{core::int} let final core::int #t14 = 0 in this.{self::Class::_#Class#initializedFinalInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#initializedFinalInstanceField} = #t14 : throw new _in::LateError::fieldADI("initializedFinalInstanceField") : #t13{core::int};
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::int? _#initializedFinalTopLevelField = null;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t15) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t15;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t16 = nonNullableUninitializedNonFinalLocal in #t16.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal") : #t16{core::int};
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t17) → dynamic
+ return nonNullableUninitializedNonFinalLocal = #t17;
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t18) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t18;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return let final core::int? #t19 = nonNullableUninitializedFinalLocal in #t19.==(null) ?{core::int} throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal") : #t19{core::int};
+ function #nonNullableUninitializedFinalLocal#set(core::int #t20) → dynamic
+ if(nonNullableUninitializedFinalLocal.==(null))
+ return nonNullableUninitializedFinalLocal = #t20;
+ else
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t21) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t21;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int
+ return let final core::int? #t22 = nonNullableInitializedNonFinalLocal in #t22.==(null) ?{core::int} nonNullableInitializedNonFinalLocal = 0 : #t22{core::int};
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t23) → dynamic
+ return nonNullableInitializedNonFinalLocal = #t23;
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ function #nonNullableInitializedFinalLocal#get() → core::int
+ return let final core::int? #t24 = nonNullableInitializedFinalLocal in #t24.==(null) ?{core::int} nonNullableInitializedFinalLocal = 0 : #t24{core::int};
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t25 = self::_#uninitializedNonFinalTopLevelField in #t25.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField") : #t25{core::int};
+static set uninitializedNonFinalTopLevelField(core::int #t26) → void
+ self::_#uninitializedNonFinalTopLevelField = #t26;
+static get uninitializedFinalTopLevelField() → core::int
+ return let final core::int? #t27 = self::_#uninitializedFinalTopLevelField in #t27.==(null) ?{core::int} throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField") : #t27{core::int};
+static set uninitializedFinalTopLevelField(core::int #t28) → void
+ if(self::_#uninitializedFinalTopLevelField.==(null))
+ self::_#uninitializedFinalTopLevelField = #t28;
+ else
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+static get initializedNonFinalTopLevelField() → core::int
+ return let final core::int? #t29 = self::_#initializedNonFinalTopLevelField in #t29.==(null) ?{core::int} self::_#initializedNonFinalTopLevelField = 0 : #t29{core::int};
+static set initializedNonFinalTopLevelField(core::int #t30) → void
+ self::_#initializedNonFinalTopLevelField = #t30;
+static get initializedFinalTopLevelField() → core::int
+ return let final core::int? #t31 = self::_#initializedFinalTopLevelField in #t31.==(null) ?{core::int} let final core::int #t32 = 0 in self::_#initializedFinalTopLevelField.==(null) ?{core::int} self::_#initializedFinalTopLevelField = #t32 : throw new _in::LateError::fieldADI("initializedFinalTopLevelField") : #t31{core::int};
+
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///main.dart:30:25 -> IntConstant(0)
+Evaluated: VariableGet @ org-dartlang-testcase:///main.dart:35:18 -> IntConstant(0)
+Evaluated: VariableGet @ org-dartlang-testcase:///main.dart:24:16 -> IntConstant(0)
+Extra constant evaluation: evaluated: 212, effectively constant: 3
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.textual_outline.expect
new file mode 100644
index 0000000..83c95c1
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.textual_outline.expect
@@ -0,0 +1,28 @@
+main() {}
+method() {}
+late int ;
+uninitializedNonFinalTopLevelField;
+late ;
+final int uninitializedFinalTopLevelField;
+late int ;
+initializedNonFinalTopLevelField = 0;
+late ;
+final int initializedFinalTopLevelField = 0;
+class Class {
+ static late int ;
+ uninitializedNonFinalStaticField;
+ static late ;
+ final int uninitializedFinalStaticField;
+ static late int ;
+ initializedNonFinalStaticField = 0;
+ static late ;
+ final int initializedFinalStaticField = 0;
+ late int ;
+ uninitializedNonFinalInstanceField;
+ late ;
+ final int uninitializedFinalInstanceField;
+ late int ;
+ initializedNonFinalInstanceField = 0;
+ late ;
+ final int initializedFinalInstanceField = 0;
+}
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.weak.expect b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.weak.expect
new file mode 100644
index 0000000..91d5d03
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.weak.expect
@@ -0,0 +1,220 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::bool _#uninitializedNonFinalStaticField#isSet = false;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::bool _#uninitializedFinalStaticField#isSet = false;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::bool _#initializedNonFinalStaticField#isSet = false;
+ static field core::int? _#initializedFinalStaticField = null;
+ static field core::bool _#initializedFinalStaticField#isSet = false;
+ late field core::int uninitializedNonFinalInstanceField;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::bool _#Class#uninitializedFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::bool _#Class#initializedNonFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ field core::bool _#Class#initializedFinalInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return self::Class::_#uninitializedNonFinalStaticField#isSet ?{core::int} let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField");
+ static set uninitializedNonFinalStaticField(core::int #t2) → void {
+ self::Class::_#uninitializedNonFinalStaticField#isSet = true;
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ }
+ static get uninitializedFinalStaticField() → core::int
+ return self::Class::_#uninitializedFinalStaticField#isSet ?{core::int} let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalStaticField");
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ else {
+ self::Class::_#uninitializedFinalStaticField#isSet = true;
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ }
+ static get initializedNonFinalStaticField() → core::int {
+ if(!self::Class::_#initializedNonFinalStaticField#isSet) {
+ self::Class::_#initializedNonFinalStaticField = 0;
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5{core::int};
+ }
+ static set initializedNonFinalStaticField(core::int #t6) → void {
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ }
+ static get initializedFinalStaticField() → core::int {
+ if(!self::Class::_#initializedFinalStaticField#isSet) {
+ final core::int #t7 = 0;
+ if(self::Class::_#initializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalStaticField");
+ self::Class::_#initializedFinalStaticField = #t7;
+ self::Class::_#initializedFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t8 = self::Class::_#initializedFinalStaticField in #t8{core::int};
+ }
+ get uninitializedFinalInstanceField() → core::int
+ return this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} ?{core::int} let final core::int? #t9 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t9{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalInstanceField");
+ set uninitializedFinalInstanceField(core::int #t10) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ else {
+ this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t10;
+ }
+ get initializedNonFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet}) {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t11 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t11{core::int};
+ }
+ set initializedNonFinalInstanceField(core::int #t12) → void {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t12;
+ }
+ get initializedFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedFinalInstanceField#isSet}) {
+ final core::int #t13 = 0;
+ if(this.{self::Class::_#Class#initializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldADI("initializedFinalInstanceField");
+ this.{self::Class::_#Class#initializedFinalInstanceField} = #t13;
+ this.{self::Class::_#Class#initializedFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t14 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t14{core::int};
+ }
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::bool _#uninitializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::bool _#uninitializedFinalTopLevelField#isSet = false;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::bool _#initializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#initializedFinalTopLevelField = null;
+static field core::bool _#initializedFinalTopLevelField#isSet = false;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t15) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t15;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ core::bool #nonNullableUninitializedNonFinalLocal#isSet = false;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return #nonNullableUninitializedNonFinalLocal#isSet ?{core::int} nonNullableUninitializedNonFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal");
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t16) → dynamic {
+ #nonNullableUninitializedNonFinalLocal#isSet = true;
+ return nonNullableUninitializedNonFinalLocal = #t16;
+ }
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t17) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t17;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ core::bool #nonNullableUninitializedFinalLocal#isSet = false;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return #nonNullableUninitializedFinalLocal#isSet ?{core::int} nonNullableUninitializedFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal");
+ function #nonNullableUninitializedFinalLocal#set(core::int #t18) → dynamic
+ if(#nonNullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ else {
+ #nonNullableUninitializedFinalLocal#isSet = true;
+ return nonNullableUninitializedFinalLocal = #t18;
+ }
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t19) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t19;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ core::bool #nonNullableInitializedNonFinalLocal#isSet = false;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedNonFinalLocal#isSet) {
+ nonNullableInitializedNonFinalLocal = 0;
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedNonFinalLocal{core::int};
+ }
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t20) → dynamic {
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ return nonNullableInitializedNonFinalLocal = #t20;
+ }
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ core::bool #nonNullableInitializedFinalLocal#isSet = false;
+ function #nonNullableInitializedFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedFinalLocal#isSet) {
+ nonNullableInitializedFinalLocal = 0;
+ #nonNullableInitializedFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedFinalLocal{core::int};
+ }
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return self::_#uninitializedNonFinalTopLevelField#isSet ?{core::int} let final core::int? #t21 = self::_#uninitializedNonFinalTopLevelField in #t21{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField");
+static set uninitializedNonFinalTopLevelField(core::int #t22) → void {
+ self::_#uninitializedNonFinalTopLevelField#isSet = true;
+ self::_#uninitializedNonFinalTopLevelField = #t22;
+}
+static get uninitializedFinalTopLevelField() → core::int
+ return self::_#uninitializedFinalTopLevelField#isSet ?{core::int} let final core::int? #t23 = self::_#uninitializedFinalTopLevelField in #t23{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField");
+static set uninitializedFinalTopLevelField(core::int #t24) → void
+ if(self::_#uninitializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+ else {
+ self::_#uninitializedFinalTopLevelField#isSet = true;
+ self::_#uninitializedFinalTopLevelField = #t24;
+ }
+static get initializedNonFinalTopLevelField() → core::int {
+ if(!self::_#initializedNonFinalTopLevelField#isSet) {
+ self::_#initializedNonFinalTopLevelField = 0;
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t25 = self::_#initializedNonFinalTopLevelField in #t25{core::int};
+}
+static set initializedNonFinalTopLevelField(core::int #t26) → void {
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ self::_#initializedNonFinalTopLevelField = #t26;
+}
+static get initializedFinalTopLevelField() → core::int {
+ if(!self::_#initializedFinalTopLevelField#isSet) {
+ final core::int #t27 = 0;
+ if(self::_#initializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalTopLevelField");
+ self::_#initializedFinalTopLevelField = #t27;
+ self::_#initializedFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t28 = self::_#initializedFinalTopLevelField in #t28{core::int};
+}
diff --git a/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..91d5d03
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/skip_late_final_uninitialized_instance_fields/main.dart.weak.transformed.expect
@@ -0,0 +1,220 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+class Class extends core::Object {
+ static field core::int? _#uninitializedNonFinalStaticField = null;
+ static field core::bool _#uninitializedNonFinalStaticField#isSet = false;
+ static field core::int? _#uninitializedFinalStaticField = null;
+ static field core::bool _#uninitializedFinalStaticField#isSet = false;
+ static field core::int? _#initializedNonFinalStaticField = null;
+ static field core::bool _#initializedNonFinalStaticField#isSet = false;
+ static field core::int? _#initializedFinalStaticField = null;
+ static field core::bool _#initializedFinalStaticField#isSet = false;
+ late field core::int uninitializedNonFinalInstanceField;
+ field core::int? _#Class#uninitializedFinalInstanceField = null;
+ field core::bool _#Class#uninitializedFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedNonFinalInstanceField = null;
+ field core::bool _#Class#initializedNonFinalInstanceField#isSet = false;
+ field core::int? _#Class#initializedFinalInstanceField = null;
+ field core::bool _#Class#initializedFinalInstanceField#isSet = false;
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ static get uninitializedNonFinalStaticField() → core::int
+ return self::Class::_#uninitializedNonFinalStaticField#isSet ?{core::int} let final core::int? #t1 = self::Class::_#uninitializedNonFinalStaticField in #t1{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalStaticField");
+ static set uninitializedNonFinalStaticField(core::int #t2) → void {
+ self::Class::_#uninitializedNonFinalStaticField#isSet = true;
+ self::Class::_#uninitializedNonFinalStaticField = #t2;
+ }
+ static get uninitializedFinalStaticField() → core::int
+ return self::Class::_#uninitializedFinalStaticField#isSet ?{core::int} let final core::int? #t3 = self::Class::_#uninitializedFinalStaticField in #t3{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalStaticField");
+ static set uninitializedFinalStaticField(core::int #t4) → void
+ if(self::Class::_#uninitializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalStaticField");
+ else {
+ self::Class::_#uninitializedFinalStaticField#isSet = true;
+ self::Class::_#uninitializedFinalStaticField = #t4;
+ }
+ static get initializedNonFinalStaticField() → core::int {
+ if(!self::Class::_#initializedNonFinalStaticField#isSet) {
+ self::Class::_#initializedNonFinalStaticField = 0;
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t5 = self::Class::_#initializedNonFinalStaticField in #t5{core::int};
+ }
+ static set initializedNonFinalStaticField(core::int #t6) → void {
+ self::Class::_#initializedNonFinalStaticField#isSet = true;
+ self::Class::_#initializedNonFinalStaticField = #t6;
+ }
+ static get initializedFinalStaticField() → core::int {
+ if(!self::Class::_#initializedFinalStaticField#isSet) {
+ final core::int #t7 = 0;
+ if(self::Class::_#initializedFinalStaticField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalStaticField");
+ self::Class::_#initializedFinalStaticField = #t7;
+ self::Class::_#initializedFinalStaticField#isSet = true;
+ }
+ return let final core::int? #t8 = self::Class::_#initializedFinalStaticField in #t8{core::int};
+ }
+ get uninitializedFinalInstanceField() → core::int
+ return this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} ?{core::int} let final core::int? #t9 = this.{self::Class::_#Class#uninitializedFinalInstanceField} in #t9{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalInstanceField");
+ set uninitializedFinalInstanceField(core::int #t10) → void
+ if(this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldAI("uninitializedFinalInstanceField");
+ else {
+ this.{self::Class::_#Class#uninitializedFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#uninitializedFinalInstanceField} = #t10;
+ }
+ get initializedNonFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet}) {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = 0;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t11 = this.{self::Class::_#Class#initializedNonFinalInstanceField} in #t11{core::int};
+ }
+ set initializedNonFinalInstanceField(core::int #t12) → void {
+ this.{self::Class::_#Class#initializedNonFinalInstanceField#isSet} = true;
+ this.{self::Class::_#Class#initializedNonFinalInstanceField} = #t12;
+ }
+ get initializedFinalInstanceField() → core::int {
+ if(!this.{self::Class::_#Class#initializedFinalInstanceField#isSet}) {
+ final core::int #t13 = 0;
+ if(this.{self::Class::_#Class#initializedFinalInstanceField#isSet})
+ throw new _in::LateError::fieldADI("initializedFinalInstanceField");
+ this.{self::Class::_#Class#initializedFinalInstanceField} = #t13;
+ this.{self::Class::_#Class#initializedFinalInstanceField#isSet} = true;
+ }
+ return let final core::int? #t14 = this.{self::Class::_#Class#initializedFinalInstanceField} in #t14{core::int};
+ }
+}
+static field core::int? _#uninitializedNonFinalTopLevelField = null;
+static field core::bool _#uninitializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#uninitializedFinalTopLevelField = null;
+static field core::bool _#uninitializedFinalTopLevelField#isSet = false;
+static field core::int? _#initializedNonFinalTopLevelField = null;
+static field core::bool _#initializedNonFinalTopLevelField#isSet = false;
+static field core::int? _#initializedFinalTopLevelField = null;
+static field core::bool _#initializedFinalTopLevelField#isSet = false;
+static method main() → dynamic {}
+static method method() → dynamic {
+ core::int? nullableUninitializedNonFinalLocal;
+ core::bool #nullableUninitializedNonFinalLocal#isSet = false;
+ function #nullableUninitializedNonFinalLocal#get() → core::int?
+ return #nullableUninitializedNonFinalLocal#isSet ?{core::int?} nullableUninitializedNonFinalLocal : throw new _in::LateError::localNI("nullableUninitializedNonFinalLocal");
+ function #nullableUninitializedNonFinalLocal#set(core::int? #t15) → dynamic {
+ #nullableUninitializedNonFinalLocal#isSet = true;
+ return nullableUninitializedNonFinalLocal = #t15;
+ }
+ core::int? nonNullableUninitializedNonFinalLocal;
+ core::bool #nonNullableUninitializedNonFinalLocal#isSet = false;
+ function #nonNullableUninitializedNonFinalLocal#get() → core::int
+ return #nonNullableUninitializedNonFinalLocal#isSet ?{core::int} nonNullableUninitializedNonFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedNonFinalLocal");
+ function #nonNullableUninitializedNonFinalLocal#set(core::int #t16) → dynamic {
+ #nonNullableUninitializedNonFinalLocal#isSet = true;
+ return nonNullableUninitializedNonFinalLocal = #t16;
+ }
+ final core::int? nullableUninitializedFinalLocal;
+ core::bool #nullableUninitializedFinalLocal#isSet = false;
+ function #nullableUninitializedFinalLocal#get() → core::int?
+ return #nullableUninitializedFinalLocal#isSet ?{core::int?} nullableUninitializedFinalLocal : throw new _in::LateError::localNI("nullableUninitializedFinalLocal");
+ function #nullableUninitializedFinalLocal#set(core::int? #t17) → dynamic
+ if(#nullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nullableUninitializedFinalLocal");
+ else {
+ #nullableUninitializedFinalLocal#isSet = true;
+ return nullableUninitializedFinalLocal = #t17;
+ }
+ final core::int? nonNullableUninitializedFinalLocal;
+ core::bool #nonNullableUninitializedFinalLocal#isSet = false;
+ function #nonNullableUninitializedFinalLocal#get() → core::int
+ return #nonNullableUninitializedFinalLocal#isSet ?{core::int} nonNullableUninitializedFinalLocal{core::int} : throw new _in::LateError::localNI("nonNullableUninitializedFinalLocal");
+ function #nonNullableUninitializedFinalLocal#set(core::int #t18) → dynamic
+ if(#nonNullableUninitializedFinalLocal#isSet)
+ throw new _in::LateError::localAI("nonNullableUninitializedFinalLocal");
+ else {
+ #nonNullableUninitializedFinalLocal#isSet = true;
+ return nonNullableUninitializedFinalLocal = #t18;
+ }
+ core::int? nullableInitializedNonFinalLocal;
+ core::bool #nullableInitializedNonFinalLocal#isSet = false;
+ function #nullableInitializedNonFinalLocal#get() → core::int? {
+ if(!#nullableInitializedNonFinalLocal#isSet) {
+ nullableInitializedNonFinalLocal = 0;
+ #nullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nullableInitializedNonFinalLocal;
+ }
+ function #nullableInitializedNonFinalLocal#set(core::int? #t19) → dynamic {
+ #nullableInitializedNonFinalLocal#isSet = true;
+ return nullableInitializedNonFinalLocal = #t19;
+ }
+ core::int? nonNullableInitializedNonFinalLocal;
+ core::bool #nonNullableInitializedNonFinalLocal#isSet = false;
+ function #nonNullableInitializedNonFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedNonFinalLocal#isSet) {
+ nonNullableInitializedNonFinalLocal = 0;
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedNonFinalLocal{core::int};
+ }
+ function #nonNullableInitializedNonFinalLocal#set(core::int #t20) → dynamic {
+ #nonNullableInitializedNonFinalLocal#isSet = true;
+ return nonNullableInitializedNonFinalLocal = #t20;
+ }
+ final core::int? nullableInitializedFinalLocal;
+ core::bool #nullableInitializedFinalLocal#isSet = false;
+ function #nullableInitializedFinalLocal#get() → core::int? {
+ if(!#nullableInitializedFinalLocal#isSet) {
+ nullableInitializedFinalLocal = 0;
+ #nullableInitializedFinalLocal#isSet = true;
+ }
+ return nullableInitializedFinalLocal;
+ }
+ final core::int? nonNullableInitializedFinalLocal;
+ core::bool #nonNullableInitializedFinalLocal#isSet = false;
+ function #nonNullableInitializedFinalLocal#get() → core::int {
+ if(!#nonNullableInitializedFinalLocal#isSet) {
+ nonNullableInitializedFinalLocal = 0;
+ #nonNullableInitializedFinalLocal#isSet = true;
+ }
+ return nonNullableInitializedFinalLocal{core::int};
+ }
+}
+static get uninitializedNonFinalTopLevelField() → core::int
+ return self::_#uninitializedNonFinalTopLevelField#isSet ?{core::int} let final core::int? #t21 = self::_#uninitializedNonFinalTopLevelField in #t21{core::int} : throw new _in::LateError::fieldNI("uninitializedNonFinalTopLevelField");
+static set uninitializedNonFinalTopLevelField(core::int #t22) → void {
+ self::_#uninitializedNonFinalTopLevelField#isSet = true;
+ self::_#uninitializedNonFinalTopLevelField = #t22;
+}
+static get uninitializedFinalTopLevelField() → core::int
+ return self::_#uninitializedFinalTopLevelField#isSet ?{core::int} let final core::int? #t23 = self::_#uninitializedFinalTopLevelField in #t23{core::int} : throw new _in::LateError::fieldNI("uninitializedFinalTopLevelField");
+static set uninitializedFinalTopLevelField(core::int #t24) → void
+ if(self::_#uninitializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldAI("uninitializedFinalTopLevelField");
+ else {
+ self::_#uninitializedFinalTopLevelField#isSet = true;
+ self::_#uninitializedFinalTopLevelField = #t24;
+ }
+static get initializedNonFinalTopLevelField() → core::int {
+ if(!self::_#initializedNonFinalTopLevelField#isSet) {
+ self::_#initializedNonFinalTopLevelField = 0;
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t25 = self::_#initializedNonFinalTopLevelField in #t25{core::int};
+}
+static set initializedNonFinalTopLevelField(core::int #t26) → void {
+ self::_#initializedNonFinalTopLevelField#isSet = true;
+ self::_#initializedNonFinalTopLevelField = #t26;
+}
+static get initializedFinalTopLevelField() → core::int {
+ if(!self::_#initializedFinalTopLevelField#isSet) {
+ final core::int #t27 = 0;
+ if(self::_#initializedFinalTopLevelField#isSet)
+ throw new _in::LateError::fieldADI("initializedFinalTopLevelField");
+ self::_#initializedFinalTopLevelField = #t27;
+ self::_#initializedFinalTopLevelField#isSet = true;
+ }
+ return let final core::int? #t28 = self::_#initializedFinalTopLevelField in #t28{core::int};
+}
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 1d7593c..ab8fac6 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -163,6 +163,7 @@
late_lowering/late_final_nullable_field_with_initializer: FormatterCrash
late_lowering/late_final_nullable_field_without_initializer: FormatterCrash
late_lowering/late_future_or: FormatterCrash
+late_lowering/late_lowering_bitmasks: FormatterCrash
late_lowering/late_nullable_field_with_initializer: FormatterCrash
late_lowering/late_nullable_field_without_initializer: FormatterCrash
late_lowering/later: FormatterCrash
@@ -170,6 +171,7 @@
late_lowering/override_getter_setter: FormatterCrash
late_lowering/uninitialized_non_nullable_late_fields: FormatterCrash
late_lowering_sentinel/late_fields: FormatterCrash
+late_lowering/skip_late_final_uninitialized_instance_fields/main: FormatterCrash
nnbd/abstract_field_errors: FormatterCrash
nnbd/covariant_late_field: FormatterCrash
nnbd/definitely_unassigned: FormatterCrash
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index deda925..32f3042 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -284,9 +284,11 @@
"status": "test/lint_test.status",
"pattern": [
"_fe_analyzer_shared/lib/.*\\.dart$",
+ "kernel/lib/.*\\.dart$",
"front_end/lib/.*\\.dart$"
],
"exclude": [
+ "kernel/lib/transformations/.*\\.dart$",
"_fe_analyzer_shared/lib/src/messages/codes_generated\\.dart$",
"front_end/lib/src/fasta/fasta_codes_cfe_generated\\.dart$"
]
diff --git a/pkg/front_end/tool/_fasta/command_line.dart b/pkg/front_end/tool/_fasta/command_line.dart
index 0404554..ed79435 100644
--- a/pkg/front_end/tool/_fasta/command_line.dart
+++ b/pkg/front_end/tool/_fasta/command_line.dart
@@ -51,7 +51,7 @@
show SchemeBasedFileSystem;
import 'package:kernel/target/targets.dart'
- show Target, getTarget, TargetFlags, targets;
+ show LateLowering, Target, getTarget, TargetFlags, targets;
class CommandLineProblem {
final Message message;
@@ -242,7 +242,9 @@
onWarning: print);
final TargetFlags flags = new TargetFlags(
- forceLateLoweringForTesting: options[Flags.forceLateLowering],
+ forceLateLoweringsForTesting: options[Flags.forceLateLowering]
+ ? LateLowering.all
+ : LateLowering.none,
forceStaticFieldLoweringForTesting:
options[Flags.forceStaticFieldLowering],
forceNoExplicitGetterCallsForTesting:
diff --git a/pkg/kernel/analysis_options.yaml b/pkg/kernel/analysis_options.yaml
index af1bb97..68fdd50 100644
--- a/pkg/kernel/analysis_options.yaml
+++ b/pkg/kernel/analysis_options.yaml
@@ -1,3 +1,19 @@
analyzer:
exclude:
- testcases/**
+
+linter:
+ rules:
+ - curly_braces_in_flow_control_structures
+ - prefer_adjacent_string_concatenation
+ - unawaited_futures
+ - recursive_getters
+ - avoid_empty_else
+ - empty_statements
+ - list_remove_unrelated_type
+ - iterable_contains_unrelated_type
+ - valid_regexps
+ - package_api_docs
+ - lines_longer_than_80_chars
+ - unrelated_type_equality_checks
+ # - always_specify_types
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index ce1824e..c1268c8 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -64,6 +64,8 @@
///
library kernel.ast;
+import 'dart:core';
+import 'dart:core' as core show MapEntry;
import 'dart:collection' show ListBase;
import 'dart:convert' show utf8;
@@ -1030,7 +1032,7 @@
}
List<Supertype> superclassConstraints() {
- var constraints = <Supertype>[];
+ List<Supertype> constraints = <Supertype>[];
// Not a mixin declaration.
if (!isMixinDeclaration) return constraints;
@@ -1077,7 +1079,7 @@
/// done automatically when accessing the lists.
void ensureLoaded() {
if (lazyBuilder != null) {
- var lazyBuilderLocal = lazyBuilder;
+ void Function() lazyBuilderLocal = lazyBuilder;
lazyBuilder = null;
lazyBuilderLocal();
}
@@ -2770,7 +2772,7 @@
void _buildLazy() {
if (lazyBuilder != null) {
- var lazyBuilderLocal = lazyBuilder;
+ void Function() lazyBuilderLocal = lazyBuilder;
lazyBuilder = null;
lazyBuilderLocal();
}
@@ -2829,9 +2831,10 @@
named.sort();
// We need create a copy of the list of type parameters, otherwise
// transformations like erasure don't work.
- var typeParametersCopy = new List<TypeParameter>.from(parent is Constructor
- ? parent.enclosingClass.typeParameters
- : typeParameters);
+ List<TypeParameter> typeParametersCopy = new List<TypeParameter>.from(
+ parent is Constructor
+ ? parent.enclosingClass.typeParameters
+ : typeParameters);
return new FunctionType(
positionalParameters.map(_getTypeOfVariable).toList(growable: false),
returnType,
@@ -3062,7 +3065,7 @@
return context.typeEnvironment.coreTypes
.rawType(superclass, context.nonNullable);
}
- var type = getStaticType(context);
+ DartType type = getStaticType(context);
while (type is TypeParameterType) {
TypeParameterType typeParameterType = type;
type =
@@ -3292,10 +3295,10 @@
@override
DartType getStaticTypeInternal(StaticTypeContext context) {
- var interfaceTarget = this.interfaceTarget;
+ Member interfaceTarget = this.interfaceTarget;
if (interfaceTarget != null) {
Class superclass = interfaceTarget.enclosingClass;
- var receiverType =
+ InterfaceType receiverType =
receiver.getStaticTypeAsInstanceOf(superclass, context);
return Substitution.fromInterfaceType(receiverType)
.substituteType(interfaceTarget.getterType);
@@ -3847,7 +3850,7 @@
}
DartType getStaticTypeInternal(StaticTypeContext context) {
- var interfaceTarget = this.interfaceTarget;
+ Member interfaceTarget = this.interfaceTarget;
if (interfaceTarget != null) {
if (interfaceTarget is Procedure &&
context.typeEnvironment
@@ -3857,9 +3860,9 @@
arguments.positional[0].getStaticType(context));
}
Class superclass = interfaceTarget.enclosingClass;
- var receiverType =
+ DartType receiverType =
receiver.getStaticTypeAsInstanceOf(superclass, context);
- var getterType = Substitution.fromInterfaceType(receiverType)
+ DartType getterType = Substitution.fromInterfaceType(receiverType)
.substituteType(interfaceTarget.getterType);
if (getterType is FunctionType) {
Substitution substitution;
@@ -3898,7 +3901,7 @@
return const DynamicType();
}
if (name.text == 'call') {
- var receiverType = receiver.getStaticType(context);
+ DartType receiverType = receiver.getStaticType(context);
if (receiverType is FunctionType) {
if (receiverType.typeParameters.length != arguments.types.length) {
return const BottomType();
@@ -7923,7 +7926,7 @@
int upper = namedParameters.length - 1;
while (lower <= upper) {
int pivot = (lower + upper) ~/ 2;
- var namedParameter = namedParameters[pivot];
+ NamedType namedParameter = namedParameters[pivot];
int comparison = name.compareTo(namedParameter.name);
if (comparison == 0) {
return namedParameter.type;
@@ -8499,9 +8502,10 @@
throw new StateError("Can't compute nullability from an absent bound.");
}
- // If a type parameter's nullability depends on itself, it is deemed 'undetermined'.
- // Currently, it's possible if the type parameter has a possibly nested FutureOr containing that type parameter.
- // If there are other ways for such a dependency to exist, they should be checked here.
+ // If a type parameter's nullability depends on itself, it is deemed
+ // 'undetermined'. Currently, it's possible if the type parameter has a
+ // possibly nested FutureOr containing that type parameter. If there are
+ // other ways for such a dependency to exist, they should be checked here.
bool nullabilityDependsOnItself = false;
{
DartType type = typeParameter.bound;
@@ -9446,8 +9450,8 @@
DartType getType(StaticTypeContext context) {
final FunctionType type = tearOffConstant.getType(context);
- final mapping = <TypeParameter, DartType>{};
- for (final parameter in type.typeParameters) {
+ final Map<TypeParameter, DartType> mapping = <TypeParameter, DartType>{};
+ for (final TypeParameter parameter in type.typeParameters) {
mapping[parameter] = types[mapping.length];
}
return substitute(type.withoutTypeParameters, mapping);
@@ -9859,7 +9863,7 @@
}
void visitIterable(Iterable<Node> nodes, Visitor visitor) {
- for (var node in nodes) {
+ for (Node node in nodes) {
node.accept(visitor);
}
}
@@ -9867,7 +9871,7 @@
void transformTypeList(List<DartType> nodes, Transformer visitor) {
int storeIndex = 0;
for (int i = 0; i < nodes.length; ++i) {
- var result = visitor.visitDartType(nodes[i]);
+ DartType result = visitor.visitDartType(nodes[i]);
if (result != null) {
nodes[storeIndex] = result;
++storeIndex;
@@ -9881,7 +9885,7 @@
void transformSupertypeList(List<Supertype> nodes, Transformer visitor) {
int storeIndex = 0;
for (int i = 0; i < nodes.length; ++i) {
- var result = visitor.visitSupertype(nodes[i]);
+ Supertype result = visitor.visitSupertype(nodes[i]);
if (result != null) {
nodes[storeIndex] = result;
++storeIndex;
@@ -9895,7 +9899,7 @@
void transformList(List<TreeNode> nodes, Transformer visitor, TreeNode parent) {
int storeIndex = 0;
for (int i = 0; i < nodes.length; ++i) {
- var result = nodes[i].accept(visitor);
+ TreeNode result = nodes[i].accept(visitor);
if (result != null) {
nodes[storeIndex] = result;
result.parent = parent;
@@ -9999,7 +10003,7 @@
return -1;
}
RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
- var offset = lineStarts[line - 1] + column - 1;
+ int offset = lineStarts[line - 1] + column - 1;
RangeError.checkValueInInterval(offset, 0, lineStarts.last, 'offset');
return offset;
}
@@ -10174,15 +10178,15 @@
return combine2Finish(object2.hashCode, object2.hashCode, 0);
}
- static int combineListHash(List list, [int hash = 1]) {
- for (var item in list) {
+ static int combineListHash(List<Object> list, [int hash = 1]) {
+ for (Object item in list) {
hash = _Hash.combine(item.hashCode, hash);
}
return hash;
}
static int combineList(List<int> hashes, int hash) {
- for (var item in hashes) {
+ for (int item in hashes) {
hash = combine(item, hash);
}
return hash;
@@ -10192,7 +10196,7 @@
if (map == null || map.isEmpty) return hash;
List<int> entryHashes = List(map.length);
int i = 0;
- for (var entry in map.entries) {
+ for (core.MapEntry entry in map.entries) {
entryHashes[i++] = combine(entry.key.hashCode, entry.value.hashCode);
}
entryHashes.sort();
@@ -10216,8 +10220,12 @@
}
int mapHashCodeOrdered(Map map, [int hash = 2]) {
- for (final Object x in map.keys) hash = _Hash.combine(x.hashCode, hash);
- for (final Object x in map.values) hash = _Hash.combine(x.hashCode, hash);
+ for (final Object x in map.keys) {
+ hash = _Hash.combine(x.hashCode, hash);
+ }
+ for (final Object x in map.values) {
+ hash = _Hash.combine(x.hashCode, hash);
+ }
return _Hash.finish(hash);
}
@@ -10256,7 +10264,7 @@
/// Annotation describing information which is not part of Dart semantics; in
/// other words, if this information (or any information it refers to) changes,
/// static analysis and runtime behavior of the library are unaffected.
-const informative = null;
+const Null informative = null;
Location _getLocationInComponent(Component component, Uri fileUri, int offset) {
if (component != null) {
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index c0af19e..70dd2ef 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -64,7 +64,7 @@
}
class _ComponentIndex {
- static const numberOfFixedFields = 10;
+ static const int numberOfFixedFields = 10;
int binaryOffsetForSourceTable;
int binaryOffsetForCanonicalNames;
@@ -145,7 +145,7 @@
int readByte() => _bytes[_byteOffset++];
int readUInt() {
- var byte = readByte();
+ int byte = readByte();
if (byte & 0x80 == 0) {
// 0xxxxxxx
return byte;
@@ -354,7 +354,8 @@
}
return new InstanceConstant(classReference, typeArguments, fieldValues);
case ConstantTag.PartialInstantiationConstant:
- final tearOffConstant = readConstantReference() as TearOffConstant;
+ final TearOffConstant tearOffConstant =
+ readConstantReference() as TearOffConstant;
final int length = readUInt();
final List<DartType> types = new List<DartType>(length);
for (int i = 0; i < length; i++) {
@@ -400,7 +401,7 @@
}
String readStringOrNullIfEmpty() {
- var string = readStringReference();
+ String string = readStringReference();
return string.isEmpty ? null : string;
}
@@ -428,7 +429,7 @@
void _fillTreeNodeList(
List<TreeNode> list, TreeNode buildObject(int index), TreeNode parent) {
- var length = readUInt();
+ int length = readUInt();
list.length = length;
for (int i = 0; i < length; ++i) {
TreeNode object = buildObject(i);
@@ -437,7 +438,7 @@
}
void _fillNonTreeNodeList(List<Node> list, Node buildObject()) {
- var length = readUInt();
+ int length = readUInt();
list.length = length;
for (int i = 0; i < length; ++i) {
Node object = buildObject();
@@ -465,7 +466,7 @@
for (int i = 0; i < length; ++i) {
int biasedParentIndex = readUInt();
String name = readStringReference();
- var parent =
+ CanonicalName parent =
biasedParentIndex == 0 ? linkRoot : _linkTable[biasedParentIndex - 1];
_linkTable[i] = parent.getChild(name);
}
@@ -497,7 +498,7 @@
}
void _readAndVerifySdkHash() {
- final sdkHash = ascii.decode(readBytes(sdkHashLength));
+ final String sdkHash = ascii.decode(readBytes(sdkHashLength));
if (!isValidSdkHash(sdkHash)) {
throw InvalidKernelSdkVersionError(sdkHash);
}
@@ -519,8 +520,8 @@
"BinaryBuilder.readComponent", () {
_checkEmptyInput();
- // Check that we have a .dill file and it has the correct version before we
- // start decoding it. Otherwise we will fail for cryptic reasons.
+ // Check that we have a .dill file and it has the correct version before
+ // we start decoding it. Otherwise we will fail for cryptic reasons.
int offset = _byteOffset;
int magic = readUint32();
if (magic != Tag.ComponentFile) {
@@ -578,8 +579,8 @@
}
}
- /// Reads a single component file from the input and loads it into [component],
- /// overwriting and reusing any existing data in the component.
+ /// Reads a single component file from the input and loads it into
+ /// [component], overwriting and reusing any existing data in the component.
///
/// When linking with a non-empty component, canonical names must have been
/// computed ahead of time.
@@ -674,9 +675,9 @@
result.libraryOffsets = new List<int>(result.libraryCount + 1);
result.componentFileSizeInBytes = readUint32();
if (result.componentFileSizeInBytes != componentFileSize) {
- throw "Malformed binary: This component file's component index indicates that"
- " the file size should be $componentFileSize but other component indexes"
- " has indicated that the size should be "
+ throw "Malformed binary: This component file's component index indicates "
+ "that the file size should be $componentFileSize but other component "
+ "indexes has indicated that the size should be "
"${result.componentFileSizeInBytes}.";
}
@@ -868,7 +869,7 @@
}
CanonicalName readCanonicalNameReference() {
- var index = readUInt();
+ int index = readUInt();
if (index == 0) return null;
return _linkTable[index - 1];
}
@@ -891,7 +892,7 @@
}
Reference readClassReference({bool allowNull: false}) {
- var name = readCanonicalNameReference();
+ CanonicalName name = readCanonicalNameReference();
if (name == null && !allowNull) {
throw 'Expected a class reference to be valid but was `null`.';
}
@@ -899,7 +900,7 @@
}
Reference readMemberReference({bool allowNull: false}) {
- var name = readCanonicalNameReference();
+ CanonicalName name = readCanonicalNameReference();
if (name == null && !allowNull) {
throw 'Expected a member reference to be valid but was `null`.';
}
@@ -907,13 +908,13 @@
}
Reference readInstanceMemberReference({bool allowNull: false}) {
- var reference = readMemberReference(allowNull: allowNull);
+ Reference reference = readMemberReference(allowNull: allowNull);
readMemberReference(allowNull: true); // Skip origin
return reference;
}
Reference getMemberReferenceFromInt(int index, {bool allowNull: false}) {
- var name = getCanonicalNameReferenceFromInt(index);
+ CanonicalName name = getCanonicalNameReferenceFromInt(index);
if (name == null && !allowNull) {
throw 'Expected a member reference to be valid but was `null`.';
}
@@ -965,7 +966,7 @@
int languageVersionMajor = readUInt();
int languageVersionMinor = readUInt();
- var canonicalName = readCanonicalNameReference();
+ CanonicalName canonicalName = readCanonicalNameReference();
Reference reference = canonicalName.getReference();
Library library = reference.node;
if (alwaysCreateNewNamedNodes) {
@@ -1041,12 +1042,12 @@
}
LibraryDependency readLibraryDependency(Library library) {
- var fileOffset = readOffset();
- var flags = readByte();
- var annotations = readExpressionList();
- var targetLibrary = readLibraryReference(allowNull: true);
- var prefixName = readStringOrNullIfEmpty();
- var names = readCombinatorList();
+ int fileOffset = readOffset();
+ int flags = readByte();
+ List<Expression> annotations = readExpressionList();
+ Reference targetLibrary = readLibraryReference(allowNull: true);
+ String prefixName = readStringOrNullIfEmpty();
+ List<Combinator> names = readCombinatorList();
return new LibraryDependency.byReference(
flags, annotations, targetLibrary, prefixName, names)
..fileOffset = fileOffset
@@ -1066,8 +1067,8 @@
}
Combinator readCombinator() {
- var isShow = readByte() == 1;
- var names = readStringReferenceList();
+ bool isShow = readByte() == 1;
+ List<String> names = readStringReferenceList();
return new Combinator(isShow, names);
}
@@ -1096,8 +1097,8 @@
}
Typedef readTypedef() {
- var canonicalName = readCanonicalNameReference();
- var reference = canonicalName.getReference();
+ CanonicalName canonicalName = readCanonicalNameReference();
+ Reference reference = canonicalName.getReference();
Typedef node = reference.node;
if (alwaysCreateNewNamedNodes) {
node = null;
@@ -1110,7 +1111,7 @@
String name = readStringReference();
node.annotations = readAnnotationList(node);
readAndPushTypeParameterList(node.typeParameters, node);
- var type = readDartType();
+ DartType type = readDartType();
readAndPushTypeParameterList(node.typeParametersOfFunctionType, node);
node.positionalParameters.clear();
node.positionalParameters.addAll(readAndPushVariableDeclarationList());
@@ -1143,8 +1144,8 @@
}
_byteOffset = savedByteOffset;
- var canonicalName = readCanonicalNameReference();
- var reference = canonicalName.getReference();
+ CanonicalName canonicalName = readCanonicalNameReference();
+ Reference reference = canonicalName.getReference();
Class node = reference.node;
if (alwaysCreateNewNamedNodes) {
node = null;
@@ -1153,14 +1154,14 @@
node = new Class(reference: reference)..dirty = false;
}
- var fileUri = readUriReference();
+ Uri fileUri = readUriReference();
node.startFileOffset = readOffset();
node.fileOffset = readOffset();
node.fileEndOffset = readOffset();
int flags = readByte();
node.flags = flags;
- var name = readStringOrNullIfEmpty();
- var annotations = readAnnotationList(node);
+ String name = readStringOrNullIfEmpty();
+ List<Expression> annotations = readAnnotationList(node);
assert(() {
debugPath.add(node.name ?? 'normal-class');
return true;
@@ -1169,8 +1170,8 @@
assert(typeParameterStack.length == 0);
readAndPushTypeParameterList(node.typeParameters, node);
- var supertype = readSupertypeOption();
- var mixedInType = readSupertypeOption();
+ Supertype supertype = readSupertypeOption();
+ Supertype mixedInType = readSupertypeOption();
_fillNonTreeNodeList(node.implementedTypes, readSupertype);
if (_disableLazyClassReading) {
readClassPartialContent(node, procedureOffsets);
@@ -1297,18 +1298,18 @@
node = new Field(null,
getterReference: getterReference, setterReference: setterReference);
}
- var fileUri = readUriReference();
+ Uri fileUri = readUriReference();
int fileOffset = readOffset();
int fileEndOffset = readOffset();
int flags = readUInt();
- var name = readName();
- var annotations = readAnnotationList(node);
+ Name name = readName();
+ List<Expression> annotations = readAnnotationList(node);
assert(() {
debugPath.add(node.name?.text ?? 'field');
return true;
}());
- var type = readDartType();
- var initializer = readExpressionOption();
+ DartType type = readDartType();
+ Expression initializer = readExpressionOption();
int transformerFlags = getAndResetTransformerFlags();
assert(((_) => true)(debugPath.removeLast()));
node.fileOffset = fileOffset;
@@ -1327,8 +1328,8 @@
Constructor readConstructor() {
int tag = readByte();
assert(tag == Tag.Constructor);
- var canonicalName = readCanonicalNameReference();
- var reference = canonicalName.getReference();
+ CanonicalName canonicalName = readCanonicalNameReference();
+ Reference reference = canonicalName.getReference();
Constructor node = reference.node;
if (alwaysCreateNewNamedNodes) {
node = null;
@@ -1336,23 +1337,23 @@
if (node == null) {
node = new Constructor(null, reference: reference);
}
- var fileUri = readUriReference();
- var startFileOffset = readOffset();
- var fileOffset = readOffset();
- var fileEndOffset = readOffset();
- var flags = readByte();
- var name = readName();
- var annotations = readAnnotationList(node);
+ Uri fileUri = readUriReference();
+ int startFileOffset = readOffset();
+ int fileOffset = readOffset();
+ int fileEndOffset = readOffset();
+ int flags = readByte();
+ Name name = readName();
+ List<Expression> annotations = readAnnotationList(node);
assert(() {
debugPath.add(node.name?.text ?? 'constructor');
return true;
}());
- var function = readFunctionNode();
+ FunctionNode function = readFunctionNode();
pushVariableDeclarations(function.positionalParameters);
pushVariableDeclarations(function.namedParameters);
_fillTreeNodeList(node.initializers, (index) => readInitializer(), node);
variableStack.length = 0;
- var transformerFlags = getAndResetTransformerFlags();
+ int transformerFlags = getAndResetTransformerFlags();
assert(((_) => true)(debugPath.removeLast()));
node.startFileOffset = startFileOffset;
node.fileOffset = fileOffset;
@@ -1369,26 +1370,26 @@
Procedure readProcedure(int endOffset) {
int tag = readByte();
assert(tag == Tag.Procedure);
- var canonicalName = readCanonicalNameReference();
- var reference = canonicalName.getReference();
+ CanonicalName canonicalName = readCanonicalNameReference();
+ Reference reference = canonicalName.getReference();
Procedure node = reference.node;
if (alwaysCreateNewNamedNodes) {
node = null;
}
- var fileUri = readUriReference();
- var startFileOffset = readOffset();
- var fileOffset = readOffset();
- var fileEndOffset = readOffset();
+ Uri fileUri = readUriReference();
+ int startFileOffset = readOffset();
+ int fileOffset = readOffset();
+ int fileEndOffset = readOffset();
int kindIndex = readByte();
- var kind = ProcedureKind.values[kindIndex];
+ ProcedureKind kind = ProcedureKind.values[kindIndex];
if (node == null) {
node = new Procedure(null, kind, null, reference: reference);
} else {
assert(node.kind == kind);
}
- var flags = readUInt();
- var name = readName();
- var annotations = readAnnotationList(node);
+ int flags = readUInt();
+ Name name = readName();
+ List<Expression> annotations = readAnnotationList(node);
assert(() {
debugPath.add(node.name?.text ?? 'procedure');
return true;
@@ -1398,13 +1399,15 @@
bool readFunctionNodeNow =
(kind == ProcedureKind.Factory && functionNodeSize <= 50) ||
_disableLazyReading;
- var forwardingStubSuperTargetReference =
+ Reference forwardingStubSuperTargetReference =
readMemberReference(allowNull: true);
- var forwardingStubInterfaceTargetReference =
+ Reference forwardingStubInterfaceTargetReference =
readMemberReference(allowNull: true);
- var memberSignatureTargetReference = readMemberReference(allowNull: true);
- var function = readFunctionNodeOption(!readFunctionNodeNow, endOffset);
- var transformerFlags = getAndResetTransformerFlags();
+ Reference memberSignatureTargetReference =
+ readMemberReference(allowNull: true);
+ FunctionNode function =
+ readFunctionNodeOption(!readFunctionNodeNow, endOffset);
+ int transformerFlags = getAndResetTransformerFlags();
assert(((_) => true)(debugPath.removeLast()));
node.startFileOffset = startFileOffset;
node.fileOffset = fileOffset;
@@ -1434,8 +1437,8 @@
RedirectingFactoryConstructor readRedirectingFactoryConstructor() {
int tag = readByte();
assert(tag == Tag.RedirectingFactoryConstructor);
- var canonicalName = readCanonicalNameReference();
- var reference = canonicalName.getReference();
+ CanonicalName canonicalName = readCanonicalNameReference();
+ Reference reference = canonicalName.getReference();
RedirectingFactoryConstructor node = reference.node;
if (alwaysCreateNewNamedNodes) {
node = null;
@@ -1443,25 +1446,25 @@
if (node == null) {
node = new RedirectingFactoryConstructor(null, reference: reference);
}
- var fileUri = readUriReference();
- var fileOffset = readOffset();
- var fileEndOffset = readOffset();
- var flags = readByte();
- var name = readName();
- var annotations = readAnnotationList(node);
+ Uri fileUri = readUriReference();
+ int fileOffset = readOffset();
+ int fileEndOffset = readOffset();
+ int flags = readByte();
+ Name name = readName();
+ List<Expression> annotations = readAnnotationList(node);
assert(() {
debugPath.add(node.name?.text ?? 'redirecting-factory-constructor');
return true;
}());
- var targetReference = readMemberReference();
- var typeArguments = readDartTypeList();
+ Reference targetReference = readMemberReference();
+ List<DartType> typeArguments = readDartTypeList();
int typeParameterStackHeight = typeParameterStack.length;
- var typeParameters = readAndPushTypeParameterList();
+ List<TypeParameter> typeParameters = readAndPushTypeParameterList();
readUInt(); // Total parameter count.
- var requiredParameterCount = readUInt();
+ int requiredParameterCount = readUInt();
int variableStackHeight = variableStack.length;
- var positional = readAndPushVariableDeclarationList();
- var named = readAndPushVariableDeclarationList();
+ List<VariableDeclaration> positional = readAndPushVariableDeclarationList();
+ List<VariableDeclaration> named = readAndPushVariableDeclarationList();
variableStack.length = variableStackHeight;
typeParameterStack.length = typeParameterStackHeight;
debugPath.removeLast();
@@ -1487,14 +1490,14 @@
case Tag.InvalidInitializer:
return new InvalidInitializer();
case Tag.FieldInitializer:
- var reference = readMemberReference();
- var value = readExpression();
+ Reference reference = readMemberReference();
+ Expression value = readExpression();
return new FieldInitializer.byReference(reference, value)
..isSynthetic = isSynthetic;
case Tag.SuperInitializer:
int offset = readOffset();
- var reference = readMemberReference();
- var arguments = readArguments();
+ Reference reference = readMemberReference();
+ Arguments arguments = readArguments();
return new SuperInitializer.byReference(reference, arguments)
..isSynthetic = isSynthetic
..fileOffset = offset;
@@ -1528,13 +1531,13 @@
AsyncMarker asyncMarker = AsyncMarker.values[readByte()];
AsyncMarker dartAsyncMarker = AsyncMarker.values[readByte()];
int typeParameterStackHeight = typeParameterStack.length;
- var typeParameters = readAndPushTypeParameterList();
+ List<TypeParameter> typeParameters = readAndPushTypeParameterList();
readUInt(); // total parameter count.
- var requiredParameterCount = readUInt();
+ int requiredParameterCount = readUInt();
int variableStackHeight = variableStack.length;
- var positional = readAndPushVariableDeclarationList();
- var named = readAndPushVariableDeclarationList();
- var returnType = readDartType();
+ List<VariableDeclaration> positional = readAndPushVariableDeclarationList();
+ List<VariableDeclaration> named = readAndPushVariableDeclarationList();
+ DartType returnType = readDartType();
int oldLabelStackBase = labelStackBase;
int oldSwitchCaseStackBase = switchCaseStackBase;
@@ -1543,7 +1546,7 @@
2; // e.g. outline has Tag.Something and Tag.EmptyStatement
}
- var body;
+ Statement body;
if (!lazyLoadBody) {
labelStackBase = labelStack.length;
switchCaseStackBase = switchCaseStack.length;
@@ -1764,20 +1767,20 @@
..fileOffset = offset;
case Tag.ListConcatenation:
int offset = readOffset();
- var typeArgument = readDartType();
+ DartType typeArgument = readDartType();
return new ListConcatenation(readExpressionList(),
typeArgument: typeArgument)
..fileOffset = offset;
case Tag.SetConcatenation:
int offset = readOffset();
- var typeArgument = readDartType();
+ DartType typeArgument = readDartType();
return new SetConcatenation(readExpressionList(),
typeArgument: typeArgument)
..fileOffset = offset;
case Tag.MapConcatenation:
int offset = readOffset();
- var keyType = readDartType();
- var valueType = readDartType();
+ DartType keyType = readDartType();
+ DartType valueType = readDartType();
return new MapConcatenation(readExpressionList(),
keyType: keyType, valueType: valueType)
..fileOffset = offset;
@@ -1852,39 +1855,39 @@
return new Throw(readExpression())..fileOffset = offset;
case Tag.ListLiteral:
int offset = readOffset();
- var typeArgument = readDartType();
+ DartType typeArgument = readDartType();
return new ListLiteral(readExpressionList(),
typeArgument: typeArgument, isConst: false)
..fileOffset = offset;
case Tag.ConstListLiteral:
int offset = readOffset();
- var typeArgument = readDartType();
+ DartType typeArgument = readDartType();
return new ListLiteral(readExpressionList(),
typeArgument: typeArgument, isConst: true)
..fileOffset = offset;
case Tag.SetLiteral:
int offset = readOffset();
- var typeArgument = readDartType();
+ DartType typeArgument = readDartType();
return new SetLiteral(readExpressionList(),
typeArgument: typeArgument, isConst: false)
..fileOffset = offset;
case Tag.ConstSetLiteral:
int offset = readOffset();
- var typeArgument = readDartType();
+ DartType typeArgument = readDartType();
return new SetLiteral(readExpressionList(),
typeArgument: typeArgument, isConst: true)
..fileOffset = offset;
case Tag.MapLiteral:
int offset = readOffset();
- var keyType = readDartType();
- var valueType = readDartType();
+ DartType keyType = readDartType();
+ DartType valueType = readDartType();
return new MapLiteral(readMapEntryList(),
keyType: keyType, valueType: valueType, isConst: false)
..fileOffset = offset;
case Tag.ConstMapLiteral:
int offset = readOffset();
- var keyType = readDartType();
- var valueType = readDartType();
+ DartType keyType = readDartType();
+ DartType valueType = readDartType();
return new MapLiteral(readMapEntryList(),
keyType: keyType, valueType: valueType, isConst: true)
..fileOffset = offset;
@@ -1894,21 +1897,21 @@
int offset = readOffset();
return new FunctionExpression(readFunctionNode())..fileOffset = offset;
case Tag.Let:
- var variable = readVariableDeclaration();
+ VariableDeclaration variable = readVariableDeclaration();
int stackHeight = variableStack.length;
pushVariableDeclaration(variable);
- var body = readExpression();
+ Expression body = readExpression();
variableStack.length = stackHeight;
return new Let(variable, body);
case Tag.BlockExpression:
int stackHeight = variableStack.length;
- var statements = readStatementList();
- var value = readExpression();
+ List<Statement> statements = readStatementList();
+ Expression value = readExpression();
variableStack.length = stackHeight;
return new BlockExpression(new Block(statements), value);
case Tag.Instantiation:
- var expression = readExpression();
- var typeArguments = readDartTypeList();
+ Expression expression = readExpression();
+ List<DartType> typeArguments = readDartTypeList();
return new Instantiation(expression, typeArguments);
case Tag.ConstantExpression:
int offset = readOffset();
@@ -1945,7 +1948,7 @@
}
Statement readStatementOrNullIfEmpty() {
- var node = readStatement();
+ Statement node = readStatement();
if (node is EmptyStatement) {
return null;
} else {
@@ -1974,7 +1977,7 @@
conditionEndOffset: readOffset(),
message: readExpressionOption());
case Tag.LabeledStatement:
- var label = new LabeledStatement(null);
+ LabeledStatement label = new LabeledStatement(null);
labelStack.add(label);
label.body = readStatement()..parent = label;
labelStack.removeLast();
@@ -1985,20 +1988,21 @@
return new BreakStatement(labelStack[labelStackBase + index])
..fileOffset = offset;
case Tag.WhileStatement:
- var offset = readOffset();
+ int offset = readOffset();
return new WhileStatement(readExpression(), readStatement())
..fileOffset = offset;
case Tag.DoStatement:
- var offset = readOffset();
+ int offset = readOffset();
return new DoStatement(readStatement(), readExpression())
..fileOffset = offset;
case Tag.ForStatement:
int variableStackHeight = variableStack.length;
- var offset = readOffset();
- var variables = readAndPushVariableDeclarationList();
- var condition = readExpressionOption();
- var updates = readExpressionList();
- var body = readStatement();
+ int offset = readOffset();
+ List<VariableDeclaration> variables =
+ readAndPushVariableDeclarationList();
+ Expression condition = readExpressionOption();
+ List<Expression> updates = readExpressionList();
+ Statement body = readStatement();
variableStack.length = variableStackHeight;
return new ForStatement(variables, condition, updates, body)
..fileOffset = offset;
@@ -2006,18 +2010,18 @@
case Tag.AsyncForInStatement:
bool isAsync = tag == Tag.AsyncForInStatement;
int variableStackHeight = variableStack.length;
- var offset = readOffset();
- var bodyOffset = readOffset();
- var variable = readAndPushVariableDeclaration();
- var iterable = readExpression();
- var body = readStatement();
+ int offset = readOffset();
+ int bodyOffset = readOffset();
+ VariableDeclaration variable = readAndPushVariableDeclaration();
+ Expression iterable = readExpression();
+ Statement body = readStatement();
variableStack.length = variableStackHeight;
return new ForInStatement(variable, iterable, body, isAsync: isAsync)
..fileOffset = offset
..bodyOffset = bodyOffset;
case Tag.SwitchStatement:
- var offset = readOffset();
- var expression = readExpression();
+ int offset = readOffset();
+ Expression expression = readExpression();
int count = readUInt();
List<SwitchCase> cases =
new List<SwitchCase>.filled(count, null, growable: true);
@@ -2058,14 +2062,14 @@
isNative: flags & YieldStatement.FlagNative != 0)
..fileOffset = offset;
case Tag.VariableDeclaration:
- var variable = readVariableDeclaration();
+ VariableDeclaration variable = readVariableDeclaration();
variableStack.add(variable); // Will be popped by the enclosing scope.
return variable;
case Tag.FunctionDeclaration:
int offset = readOffset();
- var variable = readVariableDeclaration();
+ VariableDeclaration variable = readVariableDeclaration();
variableStack.add(variable); // Will be popped by the enclosing scope.
- var function = readFunctionNode();
+ FunctionNode function = readFunctionNode();
return new FunctionDeclaration(variable, function)..fileOffset = offset;
default:
throw fail('unexpected statement tag: $tag');
@@ -2095,11 +2099,11 @@
Catch readCatch() {
int variableStackHeight = variableStack.length;
- var offset = readOffset();
- var guard = readDartType();
- var exception = readAndPushVariableDeclarationOption();
- var stackTrace = readAndPushVariableDeclarationOption();
- var body = readStatement();
+ int offset = readOffset();
+ DartType guard = readDartType();
+ VariableDeclaration exception = readAndPushVariableDeclarationOption();
+ VariableDeclaration stackTrace = readAndPushVariableDeclarationOption();
+ Statement body = readStatement();
variableStack.length = variableStackHeight;
return new Catch(exception, body, guard: guard, stackTrace: stackTrace)
..fileOffset = offset;
@@ -2107,9 +2111,9 @@
Block readBlock() {
int stackHeight = variableStack.length;
- var offset = readOffset();
- var endOffset = readOffset();
- var body = readStatementList();
+ int offset = readOffset();
+ int endOffset = readOffset();
+ List<Statement> body = readStatementList();
variableStack.length = stackHeight;
return new Block(body)
..fileOffset = offset
@@ -2118,7 +2122,7 @@
AssertBlock readAssertBlock() {
int stackHeight = variableStack.length;
- var body = readStatementList();
+ List<Statement> body = readStatementList();
variableStack.length = stackHeight;
return new AssertBlock(body);
}
@@ -2232,14 +2236,14 @@
case Tag.FunctionType:
int typeParameterStackHeight = typeParameterStack.length;
int nullabilityIndex = readByte();
- var typeParameters = readAndPushTypeParameterList();
- var requiredParameterCount = readUInt();
- var totalParameterCount = readUInt();
- var positional = readDartTypeList();
- var named = readNamedTypeList();
- var typedefType = readDartTypeOption();
+ List<TypeParameter> typeParameters = readAndPushTypeParameterList();
+ int requiredParameterCount = readUInt();
+ int totalParameterCount = readUInt();
+ List<DartType> positional = readDartTypeList();
+ List<NamedType> named = readNamedTypeList();
+ DartType typedefType = readDartTypeOption();
assert(positional.length + named.length == totalParameterCount);
- var returnType = readDartType();
+ DartType returnType = readDartType();
typeParameterStack.length = typeParameterStackHeight;
return new FunctionType(
positional, returnType, Nullability.values[nullabilityIndex],
@@ -2249,14 +2253,14 @@
typedefType: typedefType);
case Tag.SimpleFunctionType:
int nullabilityIndex = readByte();
- var positional = readDartTypeList();
- var returnType = readDartType();
+ List<DartType> positional = readDartTypeList();
+ DartType returnType = readDartType();
return new FunctionType(
positional, returnType, Nullability.values[nullabilityIndex]);
case Tag.TypeParameterType:
int declaredNullabilityIndex = readByte();
int index = readUInt();
- var bound = readDartTypeOption();
+ DartType bound = readDartTypeOption();
return new TypeParameterType(typeParameterStack[index],
Nullability.values[declaredNullabilityIndex], bound);
default:
@@ -2301,10 +2305,10 @@
}
Arguments readArguments() {
- var numArguments = readUInt();
- var typeArguments = readDartTypeList();
- var positional = readExpressionList();
- var named = readNamedExpressionList();
+ int numArguments = readUInt();
+ List<DartType> typeArguments = readDartTypeList();
+ List<Expression> positional = readExpressionList();
+ List<NamedExpression> named = readNamedExpressionList();
assert(numArguments == positional.length + named.length);
return new Arguments(positional, types: typeArguments, named: named);
}
@@ -2338,7 +2342,7 @@
}
VariableDeclaration readAndPushVariableDeclaration() {
- var variable = readVariableDeclaration();
+ VariableDeclaration variable = readVariableDeclaration();
variableStack.add(variable);
return variable;
}
@@ -2348,15 +2352,18 @@
int fileEqualsOffset = readOffset();
// The [VariableDeclaration] instance is not created at this point yet,
// so `null` is temporarily set as the parent of the annotation nodes.
- var annotations = readAnnotationList(null);
+ List<Expression> annotations = readAnnotationList(null);
int flags = readByte();
- var node = new VariableDeclaration(readStringOrNullIfEmpty(),
- type: readDartType(), initializer: readExpressionOption(), flags: flags)
+ VariableDeclaration node = new VariableDeclaration(
+ readStringOrNullIfEmpty(),
+ type: readDartType(),
+ initializer: readExpressionOption(),
+ flags: flags)
..fileOffset = offset
..fileEqualsOffset = fileEqualsOffset;
if (annotations.isNotEmpty) {
for (int i = 0; i < annotations.length; ++i) {
- var annotation = annotations[i];
+ Expression annotation = annotations[i];
annotation.parent = node;
}
node.annotations = annotations;
@@ -2395,27 +2402,28 @@
// Read the length of metadataMappings.
_byteOffset -= 4;
- final subSectionCount = readUint32();
+ final int subSectionCount = readUint32();
int endOffset = _byteOffset - 4; // End offset of the current subsection.
- for (var i = 0; i < subSectionCount; i++) {
+ for (int i = 0; i < subSectionCount; i++) {
// RList<Pair<UInt32, UInt32>> nodeOffsetToMetadataOffset
_byteOffset = endOffset - 4;
- final mappingLength = readUint32();
- final mappingStart = (endOffset - 4) - 4 * 2 * mappingLength;
+ final int mappingLength = readUint32();
+ final int mappingStart = (endOffset - 4) - 4 * 2 * mappingLength;
_byteOffset = mappingStart - 4;
// UInt32 tag (fixed size StringReference)
- final tag = _stringTable[readUint32()];
+ final String tag = _stringTable[readUint32()];
- final repository = component.metadata[tag];
+ final MetadataRepository repository = component.metadata[tag];
if (repository != null) {
// Read nodeOffsetToMetadataOffset mapping.
- final mapping = <int, int>{};
+ final Map<int, int> mapping = <int, int>{};
_byteOffset = mappingStart;
- for (var j = 0; j < mappingLength; j++) {
- final nodeOffset = readUint32();
- final metadataOffset = binaryOffsetForMetadataPayloads + readUint32();
+ for (int j = 0; j < mappingLength; j++) {
+ final int nodeOffset = readUint32();
+ final int metadataOffset =
+ binaryOffsetForMetadataPayloads + readUint32();
mapping[nodeOffset] = metadataOffset;
}
@@ -2432,7 +2440,7 @@
final int savedOffset = _byteOffset;
_byteOffset = offset;
- final metadata = repository.readFromBinary(node, this);
+ final Object metadata = repository.readFromBinary(node, this);
_byteOffset = savedOffset;
return metadata;
@@ -2458,9 +2466,9 @@
return node;
}
- for (var subsection in _subsections) {
+ for (_MetadataSubsection subsection in _subsections) {
// First check if there is any metadata associated with this node.
- final metadataOffset = subsection.mapping[nodeOffset];
+ final int metadataOffset = subsection.mapping[nodeOffset];
if (metadataOffset != null) {
subsection.repository.mapping[node] =
_readMetadata(node, subsection.repository, metadataOffset);
@@ -2472,136 +2480,137 @@
@override
DartType readDartType({bool forSupertype = false}) {
- final nodeOffset = _byteOffset;
- final result = super.readDartType(forSupertype: forSupertype);
+ final int nodeOffset = _byteOffset;
+ final DartType result = super.readDartType(forSupertype: forSupertype);
return _associateMetadata(result, nodeOffset);
}
@override
Library readLibrary(Component component, int endOffset) {
- final nodeOffset = _byteOffset;
- final result = super.readLibrary(component, endOffset);
+ final int nodeOffset = _byteOffset;
+ final Library result = super.readLibrary(component, endOffset);
return _associateMetadata(result, nodeOffset);
}
@override
Typedef readTypedef() {
- final nodeOffset = _byteOffset;
- final result = super.readTypedef();
+ final int nodeOffset = _byteOffset;
+ final Typedef result = super.readTypedef();
return _associateMetadata(result, nodeOffset);
}
@override
Class readClass(int endOffset) {
- final nodeOffset = _byteOffset;
- final result = super.readClass(endOffset);
+ final int nodeOffset = _byteOffset;
+ final Class result = super.readClass(endOffset);
return _associateMetadata(result, nodeOffset);
}
@override
Extension readExtension() {
- final nodeOffset = _byteOffset;
- final result = super.readExtension();
+ final int nodeOffset = _byteOffset;
+ final Extension result = super.readExtension();
return _associateMetadata(result, nodeOffset);
}
@override
Field readField() {
- final nodeOffset = _byteOffset;
- final result = super.readField();
+ final int nodeOffset = _byteOffset;
+ final Field result = super.readField();
return _associateMetadata(result, nodeOffset);
}
@override
Constructor readConstructor() {
- final nodeOffset = _byteOffset;
- final result = super.readConstructor();
+ final int nodeOffset = _byteOffset;
+ final Constructor result = super.readConstructor();
return _associateMetadata(result, nodeOffset);
}
@override
Procedure readProcedure(int endOffset) {
- final nodeOffset = _byteOffset;
- final result = super.readProcedure(endOffset);
+ final int nodeOffset = _byteOffset;
+ final Procedure result = super.readProcedure(endOffset);
return _associateMetadata(result, nodeOffset);
}
@override
RedirectingFactoryConstructor readRedirectingFactoryConstructor() {
- final nodeOffset = _byteOffset;
- final result = super.readRedirectingFactoryConstructor();
+ final int nodeOffset = _byteOffset;
+ final RedirectingFactoryConstructor result =
+ super.readRedirectingFactoryConstructor();
return _associateMetadata(result, nodeOffset);
}
@override
Initializer readInitializer() {
- final nodeOffset = _byteOffset;
- final result = super.readInitializer();
+ final int nodeOffset = _byteOffset;
+ final Initializer result = super.readInitializer();
return _associateMetadata(result, nodeOffset);
}
@override
FunctionNode readFunctionNode(
{bool lazyLoadBody: false, int outerEndOffset: -1}) {
- final nodeOffset = _byteOffset;
- final result = super.readFunctionNode(
+ final int nodeOffset = _byteOffset;
+ final FunctionNode result = super.readFunctionNode(
lazyLoadBody: lazyLoadBody, outerEndOffset: outerEndOffset);
return _associateMetadata(result, nodeOffset);
}
@override
Expression readExpression() {
- final nodeOffset = _byteOffset;
- final result = super.readExpression();
+ final int nodeOffset = _byteOffset;
+ final Expression result = super.readExpression();
return _associateMetadata(result, nodeOffset);
}
@override
Arguments readArguments() {
- final nodeOffset = _byteOffset;
- final result = super.readArguments();
+ final int nodeOffset = _byteOffset;
+ final Arguments result = super.readArguments();
return _associateMetadata(result, nodeOffset);
}
@override
NamedExpression readNamedExpression() {
- final nodeOffset = _byteOffset;
- final result = super.readNamedExpression();
+ final int nodeOffset = _byteOffset;
+ final NamedExpression result = super.readNamedExpression();
return _associateMetadata(result, nodeOffset);
}
@override
VariableDeclaration readVariableDeclaration() {
- final nodeOffset = _byteOffset;
- final result = super.readVariableDeclaration();
+ final int nodeOffset = _byteOffset;
+ final VariableDeclaration result = super.readVariableDeclaration();
return _associateMetadata(result, nodeOffset);
}
@override
Statement readStatement() {
- final nodeOffset = _byteOffset;
- final result = super.readStatement();
+ final int nodeOffset = _byteOffset;
+ final Statement result = super.readStatement();
return _associateMetadata(result, nodeOffset);
}
@override
Combinator readCombinator() {
- final nodeOffset = _byteOffset;
- final result = super.readCombinator();
+ final int nodeOffset = _byteOffset;
+ final Combinator result = super.readCombinator();
return _associateMetadata(result, nodeOffset);
}
@override
LibraryDependency readLibraryDependency(Library library) {
- final nodeOffset = _byteOffset;
- final result = super.readLibraryDependency(library);
+ final int nodeOffset = _byteOffset;
+ final LibraryDependency result = super.readLibraryDependency(library);
return _associateMetadata(result, nodeOffset);
}
@override
LibraryPart readLibraryPart(Library library) {
- final nodeOffset = _byteOffset;
- final result = super.readLibraryPart(library);
+ final int nodeOffset = _byteOffset;
+ final LibraryPart result = super.readLibraryPart(library);
return _associateMetadata(result, nodeOffset);
}
@@ -2619,7 +2628,7 @@
@override
Supertype readSupertype() {
- final nodeOffset = _byteOffset;
+ final int nodeOffset = _byteOffset;
InterfaceType type = super.readDartType();
return _associateMetadata(
new Supertype.byReference(type.className, type.typeArguments),
@@ -2628,8 +2637,8 @@
@override
Name readName() {
- final nodeOffset = _byteOffset;
- final result = super.readName();
+ final int nodeOffset = _byteOffset;
+ final Name result = super.readName();
return _associateMetadata(result, nodeOffset);
}
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index e7bd343..038a584 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -287,92 +287,92 @@
}
void writeNodeList(List<Node> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Node node = nodes[i];
writeNode(node);
}
}
void writeProcedureNodeList(List<Procedure> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Procedure node = nodes[i];
writeProcedureNode(node);
}
}
void writeFieldNodeList(List<Field> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Field node = nodes[i];
writeFieldNode(node);
}
}
void writeClassNodeList(List<Class> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Class node = nodes[i];
writeClassNode(node);
}
}
void writeExtensionNodeList(List<Extension> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Extension node = nodes[i];
writeExtensionNode(node);
}
}
void writeConstructorNodeList(List<Constructor> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Constructor node = nodes[i];
writeConstructorNode(node);
}
}
void writeRedirectingFactoryConstructorNodeList(
List<RedirectingFactoryConstructor> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final RedirectingFactoryConstructor node = nodes[i];
writeRedirectingFactoryConstructorNode(node);
}
}
void writeSwitchCaseNodeList(List<SwitchCase> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final SwitchCase node = nodes[i];
writeSwitchCaseNode(node);
}
}
void writeCatchNodeList(List<Catch> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Catch node = nodes[i];
writeCatchNode(node);
}
}
void writeTypedefNodeList(List<Typedef> nodes) {
- final len = nodes.length;
+ final int len = nodes.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final node = nodes[i];
+ final Typedef node = nodes[i];
writeTypedefNode(node);
}
}
@@ -538,7 +538,7 @@
Timeline.timeSync("BinaryPrinter.writeComponentFile", () {
compilationMode = component.mode;
computeCanonicalNames(component);
- final componentOffset = getBufferOffset();
+ final int componentOffset = getBufferOffset();
writeUInt32(Tag.ComponentFile);
writeUInt32(Tag.BinaryFormatVersion);
writeBytes(ascii.encode(expectedSdkHash));
@@ -605,8 +605,8 @@
void _writeNodeMetadataImpl(Node node, int nodeOffset) {
for (_MetadataSubsection subsection in _metadataSubsections) {
- final repository = subsection.repository;
- final value = repository.mapping[node];
+ final MetadataRepository<Object> repository = subsection.repository;
+ final Object value = repository.mapping[node];
if (value == null) {
continue;
}
@@ -695,7 +695,7 @@
writeUInt32(stringIndexer.put(subsection.repository.tag));
// RList<Pair<UInt32, UInt32>> nodeOffsetToMetadataOffset
- final mappingLength = subsection.metadataMapping.length;
+ final int mappingLength = subsection.metadataMapping.length;
for (int i = 0; i < mappingLength; i += 2) {
writeUInt32(subsection.metadataMapping[i]); // node offset
writeUInt32(subsection.metadataMapping[i + 1]); // metadata offset
@@ -1105,10 +1105,10 @@
}
void writeAnnotationList(List<Expression> annotations) {
- final len = annotations.length;
+ final int len = annotations.length;
writeUInt30(len);
for (int i = 0; i < len; i++) {
- final annotation = annotations[i];
+ final Expression annotation = annotations[i];
writeAnnotation(annotation);
}
}
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 5b46f8e..fced0fd 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -177,7 +177,7 @@
// If null, local development setting (e.g. run gen_kernel.dart from source),
// we put 0x00..00 into when producing, do not validate when consuming.
String get expectedSdkHash {
- final sdkHash =
+ final String sdkHash =
const String.fromEnvironment('sdk_hash', defaultValue: sdkHashNull);
if (sdkHash.length != sdkHashLength) {
throw '-Dsdk_hash=<hash> must be a ${sdkHashLength} byte string!';
diff --git a/pkg/kernel/lib/canonical_name.dart b/pkg/kernel/lib/canonical_name.dart
index 526c32e..6a1a469 100644
--- a/pkg/kernel/lib/canonical_name.dart
+++ b/pkg/kernel/lib/canonical_name.dart
@@ -105,7 +105,7 @@
}
CanonicalName getChild(String name) {
- var map = _children ??= <String, CanonicalName>{};
+ Map<String, CanonicalName> map = _children ??= <String, CanonicalName>{};
return map[name] ??= new CanonicalName._(this, name);
}
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index cb03a01..d14cfc3 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -388,7 +388,8 @@
int index = _topDownSortIndex++;
subInfo.topDownIndex = index;
_classesByTopDownIndex[index] = subInfo.classInfo.classNode;
- var subtypeSetBuilder = new _IntervalListBuilder()..addSingleton(index);
+ _IntervalListBuilder subtypeSetBuilder = new _IntervalListBuilder()
+ ..addSingleton(index);
for (_ClassInfo subtype in subInfo.classInfo.directExtenders) {
_ClassInfoSubtype subtypeInfo = _infoMap[subtype.classNode];
_topDownSortVisit(subtypeInfo);
@@ -535,8 +536,10 @@
@override
Iterable<Class> getOrderedClasses(Iterable<Class> unordered) {
- var unorderedSet = unordered.toSet();
- for (Class c in unordered) _infoMap[c]?.used = true;
+ Set<Class> unorderedSet = unordered.toSet();
+ for (Class c in unordered) {
+ _infoMap[c]?.used = true;
+ }
return _infoMap.keys.where(unorderedSet.contains);
}
@@ -564,16 +567,16 @@
List<_ClassInfo> _getRankedSuperclassInfos(_ClassInfo info) {
if (info.leastUpperBoundInfos != null) return info.leastUpperBoundInfos;
- var heap = new _LubHeap()..add(info);
- var chain = <_ClassInfo>[];
+ _LubHeap heap = new _LubHeap()..add(info);
+ List<_ClassInfo> chain = <_ClassInfo>[];
info.leastUpperBoundInfos = chain;
_ClassInfo lastInfo = null;
while (heap.isNotEmpty) {
- var nextInfo = heap.remove();
+ _ClassInfo nextInfo = heap.remove();
if (identical(nextInfo, lastInfo)) continue;
chain.add(nextInfo);
lastInfo = nextInfo;
- var classNode = nextInfo.classNode;
+ Class classNode = nextInfo.classNode;
void addToHeap(Supertype supertype) {
heap.add(infoFor(supertype.classNode));
}
@@ -682,11 +685,11 @@
if (currentDepth == 0) return candidate;
++numCandidatesAtThisDepth;
} else {
- var superType1 = identical(info1, next)
+ InterfaceType superType1 = identical(info1, next)
? type1
: Substitution.fromInterfaceType(type1).substituteType(
info1.genericSuperType[next.classNode].asInterfaceType);
- var superType2 = identical(info2, next)
+ InterfaceType superType2 = identical(info2, next)
? type2
: Substitution.fromInterfaceType(type2).substituteType(
info2.genericSuperType[next.classNode].asInterfaceType);
@@ -798,10 +801,11 @@
callback(Member declaredMember, Member interfaceMember, bool isSetter),
{bool crossGettersSetters: false}) {
_ClassInfo info = infoFor(class_);
- for (var supertype in class_.supers) {
- var superclass = supertype.classNode;
- var superGetters = getInterfaceMembers(superclass);
- var superSetters = getInterfaceMembers(superclass, setters: true);
+ for (Supertype supertype in class_.supers) {
+ Class superclass = supertype.classNode;
+ List<Member> superGetters = getInterfaceMembers(superclass);
+ List<Member> superSetters =
+ getInterfaceMembers(superclass, setters: true);
_reportOverrides(_buildDeclaredMembers(class_, info, setters: false),
superGetters, callback);
_reportOverrides(_buildDeclaredMembers(class_, info, setters: true),
@@ -837,7 +841,7 @@
@override
List<Supertype> genericSupertypesOf(Class class_) {
- final supertypes = infoFor(class_).genericSuperType;
+ Map<Class, Supertype> supertypes = infoFor(class_).genericSuperType;
if (supertypes == null) return const <Supertype>[];
return supertypes.values.toList();
}
@@ -1017,19 +1021,22 @@
for (_ClassInfo info in _infoMap.values) {
for (_ClassInfo subInfo in info.directExtenders) {
- if (!_infoMap.containsKey(subInfo.classNode))
+ if (!_infoMap.containsKey(subInfo.classNode)) {
throw new StateError(
"Found $subInfo (${subInfo.classNode}) in directExtenders");
+ }
}
for (_ClassInfo subInfo in info.directMixers) {
- if (!_infoMap.containsKey(subInfo.classNode))
+ if (!_infoMap.containsKey(subInfo.classNode)) {
throw new StateError(
"Found $subInfo (${subInfo.classNode}) in directMixers");
+ }
}
for (_ClassInfo subInfo in info.directImplementers) {
- if (!_infoMap.containsKey(subInfo.classNode))
+ if (!_infoMap.containsKey(subInfo.classNode)) {
throw new StateError(
"Found $subInfo (${subInfo.classNode}) in directImplementers");
+ }
}
}
return true;
@@ -1045,14 +1052,14 @@
if (type.classNode == superclass) {
return superclass.asThisSupertype;
}
- var map = infoFor(type.classNode)?.genericSuperType;
+ Map<Class, Supertype> map = infoFor(type.classNode)?.genericSuperType;
return map == null ? null : map[superclass];
}
void _initialize(List<Library> libraries) {
// Build the class ordering based on a topological sort.
- for (var library in libraries) {
- for (var classNode in library.classes) {
+ for (Library library in libraries) {
+ for (Class classNode in library.classes) {
_topologicalSortVisit(classNode, new Set<Class>());
}
knownLibraries.add(library);
@@ -1079,7 +1086,7 @@
if (class_.mixedInType != null) {
_infoMap[class_.mixedInType.classNode].directMixers.add(info);
}
- for (var supertype in class_.implementedTypes) {
+ for (Supertype supertype in class_.implementedTypes) {
_infoMap[supertype.classNode].directImplementers.add(info);
}
_collectSupersForClass(class_);
@@ -1114,7 +1121,7 @@
int _topSortIndex = 0;
int _topologicalSortVisit(Class classNode, Set<Class> beingVisited,
{List<Class> orderedList}) {
- var info = _infoMap[classNode];
+ _ClassInfo info = _infoMap[classNode];
if (info != null) {
return info.depth;
}
@@ -1138,7 +1145,7 @@
_topologicalSortVisit(classNode.mixedInType.classNode, beingVisited,
orderedList: orderedList));
}
- for (var supertype in classNode.implementedTypes) {
+ for (Supertype supertype in classNode.implementedTypes) {
superDepth = max(
superDepth,
_topologicalSortVisit(supertype.classNode, beingVisited,
@@ -1376,7 +1383,7 @@
// Copy over all transitive generic super types, and substitute the
// free variables with those provided in [supertype].
Class superclass = supertype.classNode;
- var substitution = Substitution.fromPairs(
+ Substitution substitution = Substitution.fromPairs(
superclass.typeParameters, supertype.typeArguments);
subInfo.genericSuperType ??= <Class, Supertype>{};
subInfo.genericSuperTypes ??= <Class, List<Supertype>>{};
@@ -1396,9 +1403,9 @@
void _collectSupersForClass(Class class_) {
_ClassInfo info = _infoMap[class_];
- var superclassSetBuilder = new _IntervalListBuilder()
+ _IntervalListBuilder superclassSetBuilder = new _IntervalListBuilder()
..addSingleton(info.topologicalIndex);
- var supertypeSetBuilder = new _IntervalListBuilder()
+ _IntervalListBuilder supertypeSetBuilder = new _IntervalListBuilder()
..addSingleton(info.topologicalIndex);
if (class_.supertype != null) {
@@ -1429,9 +1436,9 @@
/// The more numbers are condensed near the beginning, the more efficient the
/// internal data structure is.
List<int> getExpenseHistogram() {
- var result = <int>[];
+ List<int> result = <int>[];
for (Class class_ in _infoMap.keys) {
- var info = _infoMap[class_];
+ _ClassInfo info = _infoMap[class_];
int intervals = info.supertypeIntervalList.length ~/ 2;
if (intervals >= result.length) {
int oldLength = result.length;
@@ -1452,7 +1459,7 @@
int intervals = 0;
int sizes = 0;
for (Class class_ in _infoMap.keys) {
- var info = _infoMap[class_];
+ _ClassInfo info = _infoMap[class_];
intervals += (info.superclassIntervalList.length +
info.supertypeIntervalList.length) ~/
2;
@@ -1521,7 +1528,7 @@
}
}
// Copy the results over to a typed array of the correct length.
- var result = new Uint32List(storeIndex);
+ Uint32List result = new Uint32List(storeIndex);
for (int i = 0; i < storeIndex; ++i) {
result[i] = events[i];
}
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 950d052..b457805 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -103,6 +103,24 @@
return result;
}
+ /// Root entry point for cloning a subtree within the same context where the
+ /// file offsets are valid.
+ T cloneInContext<T extends TreeNode>(T node) {
+ assert(_activeFileUri == null);
+ _activeFileUri = _activeFileUriFromContext(node);
+ final TreeNode result = clone<T>(node);
+ _activeFileUri = null;
+ return result;
+ }
+
+ Uri _activeFileUriFromContext(TreeNode node) {
+ while (node != null) {
+ if (node is FileUriNode && node.fileUri != null) return node.fileUri;
+ node = node.parent;
+ }
+ return null;
+ }
+
DartType visitType(DartType type) {
return substitute(type, typeSubstitution);
}
@@ -318,7 +336,7 @@
}
visitLet(Let node) {
- var newVariable = clone(node.variable);
+ VariableDeclaration newVariable = clone(node.variable);
return new Let(newVariable, clone(node.body));
}
@@ -370,13 +388,13 @@
}
visitForStatement(ForStatement node) {
- var variables = node.variables.map(clone).toList();
+ List<VariableDeclaration> variables = node.variables.map(clone).toList();
return new ForStatement(variables, cloneOptional(node.condition),
node.updates.map(clone).toList(), clone(node.body));
}
visitForInStatement(ForInStatement node) {
- var newVariable = clone(node.variable);
+ VariableDeclaration newVariable = clone(node.variable);
return new ForInStatement(
newVariable, clone(node.iterable), clone(node.body),
isAsync: node.isAsync)
@@ -396,7 +414,7 @@
}
visitSwitchCase(SwitchCase node) {
- var switchCase = switchCases[node];
+ SwitchCase switchCase = switchCases[node];
switchCase.body = clone(node.body)..parent = switchCase;
return switchCase;
}
@@ -420,8 +438,8 @@
}
visitCatch(Catch node) {
- var newException = cloneOptional(node.exception);
- var newStackTrace = cloneOptional(node.stackTrace);
+ VariableDeclaration newException = cloneOptional(node.exception);
+ VariableDeclaration newStackTrace = cloneOptional(node.stackTrace);
return new Catch(newException, clone(node.body),
stackTrace: newStackTrace, guard: visitType(node.guard));
}
@@ -446,7 +464,7 @@
}
visitFunctionDeclaration(FunctionDeclaration node) {
- var newVariable = clone(node.variable);
+ VariableDeclaration newVariable = clone(node.variable);
return new FunctionDeclaration(newVariable, clone(node.function));
}
@@ -487,9 +505,11 @@
visitFunctionNode(FunctionNode node) {
prepareTypeParameters(node.typeParameters);
- var typeParameters = node.typeParameters.map(clone).toList();
- var positional = node.positionalParameters.map(clone).toList();
- var named = node.namedParameters.map(clone).toList();
+ List<TypeParameter> typeParameters =
+ node.typeParameters.map(clone).toList();
+ List<VariableDeclaration> positional =
+ node.positionalParameters.map(clone).toList();
+ List<VariableDeclaration> named = node.namedParameters.map(clone).toList();
return new FunctionNode(cloneFunctionNodeBody(node),
typeParameters: typeParameters,
positionalParameters: positional,
diff --git a/pkg/kernel/lib/error_formatter.dart b/pkg/kernel/lib/error_formatter.dart
index 7bb8974..42265e7 100644
--- a/pkg/kernel/lib/error_formatter.dart
+++ b/pkg/kernel/lib/error_formatter.dart
@@ -37,15 +37,15 @@
String sourceLine = null;
// Try finding original source line.
- final fileOffset = _findFileOffset(where);
+ final int fileOffset = _findFileOffset(where);
if (fileOffset != TreeNode.noOffset) {
- final fileUri = _fileUriOf(context);
+ final Uri fileUri = _fileUriOf(context);
- final component = context.enclosingComponent;
- final source = component.uriToSource[fileUri];
- final location = component.getLocation(fileUri, fileOffset);
- final lineStart = source.lineStarts[location.line - 1];
- final lineEnd = (location.line < source.lineStarts.length)
+ final Component component = context.enclosingComponent;
+ final Source source = component.uriToSource[fileUri];
+ final Location location = component.getLocation(fileUri, fileOffset);
+ final int lineStart = source.lineStarts[location.line - 1];
+ final int lineEnd = (location.line < source.lineStarts.length)
? source.lineStarts[location.line]
: (source.source.length - 1);
if (lineStart < source.source.length &&
@@ -58,16 +58,17 @@
}
// Find the name of the enclosing member.
- var name = "", body = context;
+ String name = "";
+ dynamic body = context;
if (context is Class || context is Library) {
name = context.name;
} else if (context is Procedure || context is Constructor) {
- final parent = context.parent;
- final parentName =
+ final dynamic parent = context.parent;
+ final String parentName =
parent is Class ? parent.name : (parent as Library).name;
name = "${parentName}::${context.name.text}";
} else {
- final field = context as Field;
+ final Field field = context as Field;
if (where is Field) {
name = "${field.parent}.${field.name}";
} else {
@@ -114,7 +115,7 @@
}
static Member _findEnclosingMember(TreeNode n) {
- var context = n;
+ TreeNode context = n;
while (context is! Member) {
context = context.parent;
}
@@ -125,7 +126,7 @@
/// Extension of a [Printer] that highlights the given node using ANSI
/// escape sequences.
class HighlightingPrinter extends Printer {
- final highlight;
+ final Node highlight;
HighlightingPrinter(this.highlight)
: super(new StringBuffer(), syntheticNames: globalDebuggingNames);
@@ -133,8 +134,8 @@
@override
bool shouldHighlight(Node node) => highlight == node;
- static const kHighlightStart = ansiRed;
- static const kHighlightEnd = ansiReset;
+ static const String kHighlightStart = ansiRed;
+ static const String kHighlightEnd = ansiReset;
@override
void startHighlight(Node node) {
@@ -150,7 +151,7 @@
/// representation of the [highlight] node.
static String stringifyContainingLines(Node node, Node highlight) {
if (node == highlight) {
- final firstLine = debugNodeToString(node).split('\n').first;
+ final String firstLine = debugNodeToString(node).split('\n').first;
return "${kHighlightStart}${firstLine}${kHighlightEnd}";
}
@@ -161,7 +162,7 @@
}
static Iterable<String> _onlyHighlightedLines(String text) sync* {
- for (var line
+ for (String line
in text.split('\n').skipWhile((l) => !l.contains(kHighlightStart))) {
yield line;
if (line.contains(kHighlightEnd)) {
@@ -171,7 +172,7 @@
}
}
-const ansiBlue = "\u001b[1;34m";
-const ansiYellow = "\u001b[1;33m";
-const ansiRed = "\u001b[1;31m";
-const ansiReset = "\u001b[0;0m";
+const String ansiBlue = "\u001b[1;34m";
+const String ansiYellow = "\u001b[1;33m";
+const String ansiRed = "\u001b[1;31m";
+const String ansiReset = "\u001b[0;0m";
diff --git a/pkg/kernel/lib/external_name.dart b/pkg/kernel/lib/external_name.dart
index 6577041..157981d 100644
--- a/pkg/kernel/lib/external_name.dart
+++ b/pkg/kernel/lib/external_name.dart
@@ -20,7 +20,7 @@
return null;
}
for (final Expression annotation in procedure.annotations) {
- final value = _getExternalNameValue(annotation);
+ final String value = _getExternalNameValue(annotation);
if (value != null) {
return value;
}
@@ -30,9 +30,9 @@
/// Returns native extension URIs for given [library].
List<String> getNativeExtensionUris(Library library) {
- final uris = <String>[];
- for (var annotation in library.annotations) {
- final value = _getExternalNameValue(annotation);
+ final List<String> uris = <String>[];
+ for (Expression annotation in library.annotations) {
+ final String value = _getExternalNameValue(annotation);
if (value != null) {
uris.add(value);
}
@@ -46,7 +46,7 @@
return (annotation.arguments.positional.single as StringLiteral).value;
}
} else if (annotation is ConstantExpression) {
- final constant = annotation.constant;
+ final Constant constant = annotation.constant;
if (constant is InstanceConstant) {
if (_isExternalName(constant.classNode)) {
return (constant.fieldValues.values.single as StringConstant).value;
diff --git a/pkg/kernel/lib/import_table.dart b/pkg/kernel/lib/import_table.dart
index 06d9051..051d4ab 100644
--- a/pkg/kernel/lib/import_table.dart
+++ b/pkg/kernel/lib/import_table.dart
@@ -76,8 +76,8 @@
void addLibraryImport(Library target) {
if (target == referenceLibrary) return; // Self-reference is special.
if (target == null) return;
- var referenceUri = referenceLibrary.importUri;
- var targetUri = target.importUri;
+ Uri referenceUri = referenceLibrary.importUri;
+ Uri targetUri = target.importUri;
if (targetUri == null) {
throw '$referenceUri cannot refer to library without an import URI';
}
diff --git a/pkg/kernel/lib/kernel.dart b/pkg/kernel/lib/kernel.dart
index 8504ef3..f30a6cd 100644
--- a/pkg/kernel/lib/kernel.dart
+++ b/pkg/kernel/lib/kernel.dart
@@ -39,14 +39,14 @@
}
Future writeComponentToBinary(Component component, String path) {
- var sink;
+ IOSink sink;
if (path == 'null' || path == 'stdout') {
sink = stdout.nonBlocking;
} else {
sink = new File(path).openWrite();
}
- var future;
+ Future future;
try {
new BinaryPrinter(sink).writeComponentFile(component);
} finally {
diff --git a/pkg/kernel/lib/library_index.dart b/pkg/kernel/lib/library_index.dart
index 8dbb8ee..d8e36e7 100644
--- a/pkg/kernel/lib/library_index.dart
+++ b/pkg/kernel/lib/library_index.dart
@@ -22,9 +22,9 @@
/// Indexes the libraries with the URIs given in [libraryUris].
LibraryIndex(Component component, Iterable<String> libraryUris) {
- var libraryUriSet = libraryUris.toSet();
- for (var library in component.libraries) {
- var uri = '${library.importUri}';
+ Set<String> libraryUriSet = libraryUris.toSet();
+ for (Library library in component.libraries) {
+ String uri = '${library.importUri}';
if (libraryUriSet.contains(uri)) {
_libraries[uri] = new _ClassTable(library);
}
@@ -37,7 +37,7 @@
/// Indexes `dart:` libraries.
LibraryIndex.coreLibraries(Component component) {
- for (var library in component.libraries) {
+ for (Library library in component.libraries) {
if (library.importUri.scheme == 'dart') {
_libraries['${library.importUri}'] = new _ClassTable(library);
}
@@ -49,7 +49,7 @@
/// Consider using another constructor to only index the libraries that
/// are needed.
LibraryIndex.all(Component component) {
- for (var library in component.libraries) {
+ for (Library library in component.libraries) {
_libraries['${library.importUri}'] = new _ClassTable(library);
}
}
@@ -139,10 +139,10 @@
if (_classes == null) {
_classes = <String, _MemberTable>{};
_classes[LibraryIndex.topLevel] = new _MemberTable.topLevel(this);
- for (var class_ in library.classes) {
+ for (Class class_ in library.classes) {
_classes[class_.name] = new _MemberTable.fromClass(this, class_);
}
- for (var extension_ in library.extensions) {
+ for (Extension extension_ in library.extensions) {
_classes[extension_.name] =
new _MemberTable.fromExtension(this, extension_);
}
@@ -163,7 +163,7 @@
}
_MemberTable _getClassIndex(String name) {
- var indexer = classes[name];
+ _MemberTable indexer = classes[name];
if (indexer == null) {
throw "Class '$name' not found in $containerName";
}
@@ -237,17 +237,20 @@
String getDisambiguatedExtensionName(
ExtensionMemberDescriptor extensionMember) {
- if (extensionMember.kind == ExtensionMemberKind.TearOff)
+ if (extensionMember.kind == ExtensionMemberKind.TearOff) {
return LibraryIndex.tearoffPrefix + extensionMember.name.text;
- if (extensionMember.kind == ExtensionMemberKind.Getter)
+ }
+ if (extensionMember.kind == ExtensionMemberKind.Getter) {
return LibraryIndex.getterPrefix + extensionMember.name.text;
- if (extensionMember.kind == ExtensionMemberKind.Setter)
+ }
+ if (extensionMember.kind == ExtensionMemberKind.Setter) {
return LibraryIndex.setterPrefix + extensionMember.name.text;
+ }
return extensionMember.name.text;
}
void addExtensionMember(ExtensionMemberDescriptor extensionMember) {
- final replacement = extensionMember.member.node;
+ final NamedNode replacement = extensionMember.member.node;
if (replacement is! Member) return;
Member member = replacement;
if (member.name.isPrivate && member.name.library != library) {
@@ -256,7 +259,7 @@
return;
}
- final name = getDisambiguatedExtensionName(extensionMember);
+ final String name = getDisambiguatedExtensionName(extensionMember);
_members[name] = replacement;
}
@@ -271,12 +274,12 @@
}
Member getMember(String name) {
- var member = members[name];
+ Member member = members[name];
if (member == null) {
String message = "A member with disambiguated name '$name' was not found "
"in $containerName";
- var getter = LibraryIndex.getterPrefix + name;
- var setter = LibraryIndex.setterPrefix + name;
+ String getter = LibraryIndex.getterPrefix + name;
+ String setter = LibraryIndex.setterPrefix + name;
if (members[getter] != null || members[setter] != null) {
throw "$message. Did you mean '$getter' or '$setter'?";
}
diff --git a/pkg/kernel/lib/naive_type_checker.dart b/pkg/kernel/lib/naive_type_checker.dart
index 2eb77b3..6f8d66d 100644
--- a/pkg/kernel/lib/naive_type_checker.dart
+++ b/pkg/kernel/lib/naive_type_checker.dart
@@ -41,9 +41,9 @@
@override
void checkOverride(
Class host, Member ownMember, Member superMember, bool isSetter) {
- final ownMemberIsFieldOrAccessor =
+ final bool ownMemberIsFieldOrAccessor =
ownMember is Field || (ownMember as Procedure).isAccessor;
- final superMemberIsFieldOrAccessor =
+ final bool superMemberIsFieldOrAccessor =
superMember is Field || (superMember as Procedure).isAccessor;
// TODO: move to error reporting code
@@ -51,7 +51,7 @@
if (m is Field) {
return 'field';
} else {
- final p = m as Procedure;
+ final Procedure p = m as Procedure;
if (p.isGetter) {
return 'getter';
} else if (p.isSetter) {
@@ -75,7 +75,7 @@
if (isSetter) {
final DartType ownType = setterType(host, ownMember);
final DartType superType = setterType(host, superMember);
- final isCovariant = ownMember is Field
+ final bool isCovariant = ownMember is Field
? ownMember.isCovariant
: ownMember.function.positionalParameters[0].isCovariant;
if (!_isValidParameterOverride(isCovariant, ownType, superType)) {
@@ -99,7 +99,7 @@
}
}
} else {
- final msg = _checkFunctionOverride(host, ownMember, superMember);
+ final String msg = _checkFunctionOverride(host, ownMember, superMember);
if (msg != null) {
return failures.reportInvalidOverride(ownMember, superMember, msg);
}
@@ -119,7 +119,7 @@
}
Substitution _makeSubstitutionForMember(Class host, Member member) {
- final hostType =
+ final Supertype hostType =
hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
return Substitution.fromSupertype(hostType);
}
@@ -158,10 +158,11 @@
}
if (ownFunction.typeParameters.isNotEmpty) {
- final typeParameterMap = <TypeParameter, DartType>{};
+ final Map<TypeParameter, DartType> typeParameterMap =
+ <TypeParameter, DartType>{};
for (int i = 0; i < ownFunction.typeParameters.length; ++i) {
- var subParameter = ownFunction.typeParameters[i];
- var superParameter = superFunction.typeParameters[i];
+ TypeParameter subParameter = ownFunction.typeParameters[i];
+ TypeParameter superParameter = superFunction.typeParameters[i];
typeParameterMap[subParameter] = new TypeParameterType.forAlphaRenaming(
subParameter, superParameter);
}
@@ -169,9 +170,9 @@
ownSubstitution = Substitution.combine(
ownSubstitution, Substitution.fromMap(typeParameterMap));
for (int i = 0; i < ownFunction.typeParameters.length; ++i) {
- var subParameter = ownFunction.typeParameters[i];
- var superParameter = superFunction.typeParameters[i];
- var subBound = ownSubstitution.substituteType(subParameter.bound);
+ TypeParameter subParameter = ownFunction.typeParameters[i];
+ TypeParameter superParameter = superFunction.typeParameters[i];
+ DartType subBound = ownSubstitution.substituteType(subParameter.bound);
if (!_isSubtypeOf(
superSubstitution.substituteType(superParameter.bound), subBound)) {
return 'type parameters have incompatible bounds';
@@ -181,13 +182,15 @@
if (!_isSubtypeOf(ownSubstitution.substituteType(ownFunction.returnType),
superSubstitution.substituteType(superFunction.returnType))) {
- return 'return type of override ${ownFunction.returnType} is not a subtype'
- ' of ${superFunction.returnType}';
+ return 'return type of override ${ownFunction.returnType} is not a'
+ ' subtype of ${superFunction.returnType}';
}
for (int i = 0; i < superFunction.positionalParameters.length; ++i) {
- final ownParameter = ownFunction.positionalParameters[i];
- final superParameter = superFunction.positionalParameters[i];
+ final VariableDeclaration ownParameter =
+ ownFunction.positionalParameters[i];
+ final VariableDeclaration superParameter =
+ superFunction.positionalParameters[i];
if (!_isValidParameterOverride(
ownParameter.isCovariant,
ownSubstitution.substituteType(ownParameter.type),
@@ -206,11 +209,13 @@
// Note: FunctionNode.namedParameters are not sorted so we convert them
// to map to make lookup faster.
- final ownParameters = new Map<String, VariableDeclaration>.fromIterable(
- ownFunction.namedParameters,
- key: (v) => v.name);
+ final Map<String, VariableDeclaration> ownParameters =
+ new Map<String, VariableDeclaration>.fromIterable(
+ ownFunction.namedParameters,
+ key: (v) => v.name);
for (VariableDeclaration superParameter in superFunction.namedParameters) {
- final ownParameter = ownParameters[superParameter.name];
+ final VariableDeclaration ownParameter =
+ ownParameters[superParameter.name];
if (ownParameter == null) {
return 'override is missing ${superParameter.name} parameter';
}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 7c5ee41..ac64f2c 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -438,7 +438,7 @@
assert(bottomType == const NeverType(Nullability.nonNullable) ||
bottomType is NullType);
List<TypeArgumentIssue> result;
- var substitutionMap = <TypeParameter, DartType>{};
+ Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
for (int i = 0; i < arguments.length; ++i) {
substitutionMap[parameters[i]] = arguments[i];
}
@@ -519,10 +519,10 @@
return new TypedefType(
type.typedefNode, type.nullability, replacedTypeArguments);
} else if (type is FunctionType) {
- var replacedReturnType = convertSuperBoundedToRegularBounded(
+ DartType replacedReturnType = convertSuperBoundedToRegularBounded(
clientLibrary, typeEnvironment, type.returnType, bottomType,
isCovariant: isCovariant);
- var replacedPositionalParameters =
+ List<DartType> replacedPositionalParameters =
new List<DartType>(type.positionalParameters.length);
for (int i = 0; i < replacedPositionalParameters.length; i++) {
replacedPositionalParameters[i] = convertSuperBoundedToRegularBounded(
@@ -532,7 +532,7 @@
bottomType,
isCovariant: !isCovariant);
}
- var replacedNamedParameters =
+ List<NamedType> replacedNamedParameters =
new List<NamedType>(type.namedParameters.length);
for (int i = 0; i < replacedNamedParameters.length; i++) {
replacedNamedParameters[i] = new NamedType(
diff --git a/pkg/kernel/lib/src/merge_visitor.dart b/pkg/kernel/lib/src/merge_visitor.dart
index 4b1e68b..a3909da 100644
--- a/pkg/kernel/lib/src/merge_visitor.dart
+++ b/pkg/kernel/lib/src/merge_visitor.dart
@@ -283,8 +283,9 @@
TypedefType a, TypedefType b, Nullability nullability) {
assert(a.typedefNode == b.typedefNode);
assert(a.typeArguments.length == b.typeArguments.length);
- if (a.typeArguments.isEmpty)
+ if (a.typeArguments.isEmpty) {
return new TypedefType(a.typedefNode, nullability);
+ }
List<DartType> newTypeArguments =
new List<DartType>(a.typeArguments.length);
for (int i = 0; i < a.typeArguments.length; i++) {
diff --git a/pkg/kernel/lib/src/tool/batch_util.dart b/pkg/kernel/lib/src/tool/batch_util.dart
index c3cccb6..d0482f5 100644
--- a/pkg/kernel/lib/src/tool/batch_util.dart
+++ b/pkg/kernel/lib/src/tool/batch_util.dart
@@ -22,7 +22,7 @@
Future runBatch(BatchCallback callback) async {
int totalTests = 0;
int testsFailed = 0;
- var watch = new Stopwatch()..start();
+ Stopwatch watch = new Stopwatch()..start();
print('>>> BATCH START');
Stream input = stdin.transform(utf8.decoder).transform(new LineSplitter());
await for (String line in input) {
@@ -33,9 +33,9 @@
break;
}
++totalTests;
- var arguments = line.split(new RegExp(r'\s+'));
+ List<String> arguments = line.split(new RegExp(r'\s+'));
try {
- var outcome = await callback(arguments);
+ CompilerOutcome outcome = await callback(arguments);
stderr.writeln('>>> EOF STDERR');
if (outcome == CompilerOutcome.Ok) {
print('>>> TEST PASS ${watch.elapsedMilliseconds}ms');
diff --git a/pkg/kernel/lib/src/tool/command_line_util.dart b/pkg/kernel/lib/src/tool/command_line_util.dart
index d6f3f61..1abadb2 100644
--- a/pkg/kernel/lib/src/tool/command_line_util.dart
+++ b/pkg/kernel/lib/src/tool/command_line_util.dart
@@ -19,8 +19,8 @@
static requireVariableArgumentCount(
List<int> ok, List<String> args, void Function() usage) {
if (!ok.contains(args.length)) {
- print(
- "Expected the argument count to be one of ${ok}, got ${args.length}.");
+ print("Expected the argument count to be one of ${ok}, got "
+ "${args.length}.");
usage();
}
}
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 93ea3c9..62f7def 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -13,7 +13,7 @@
class TargetFlags {
final bool trackWidgetCreation;
- final bool forceLateLoweringForTesting;
+ final int forceLateLoweringsForTesting;
final bool forceLateLoweringSentinelForTesting;
final bool forceStaticFieldLoweringForTesting;
final bool forceNoExplicitGetterCallsForTesting;
@@ -21,7 +21,7 @@
const TargetFlags(
{this.trackWidgetCreation = false,
- this.forceLateLoweringForTesting = false,
+ this.forceLateLoweringsForTesting = LateLowering.none,
this.forceLateLoweringSentinelForTesting = false,
this.forceStaticFieldLoweringForTesting = false,
this.forceNoExplicitGetterCallsForTesting = false,
@@ -31,7 +31,7 @@
if (identical(this, other)) return true;
return other is TargetFlags &&
trackWidgetCreation == other.trackWidgetCreation &&
- forceLateLoweringForTesting == other.forceLateLoweringForTesting &&
+ forceLateLoweringsForTesting == other.forceLateLoweringsForTesting &&
forceLateLoweringSentinelForTesting ==
other.forceLateLoweringSentinelForTesting &&
forceStaticFieldLoweringForTesting ==
@@ -45,7 +45,7 @@
int hash = 485786;
hash = 0x3fffffff & (hash * 31 + (hash ^ trackWidgetCreation.hashCode));
hash = 0x3fffffff &
- (hash * 31 + (hash ^ forceLateLoweringForTesting.hashCode));
+ (hash * 31 + (hash ^ forceLateLoweringsForTesting.hashCode));
hash = 0x3fffffff &
(hash * 31 + (hash ^ forceLateLoweringSentinelForTesting.hashCode));
hash = 0x3fffffff &
@@ -281,12 +281,43 @@
/// literals (for const set literals).
bool get supportsSetLiterals => true;
- /// Whether late fields and variable are support by this target.
+ /// Bit mask of [LateLowering] values for the late lowerings that should
+ /// be performed by the CFE.
///
- /// If `false`, late fields and variables are lowered fields, getter, setters
- /// etc. that provide equivalent semantics. See `pkg/kernel/nnbd_api.md` for
- /// details.
- bool get supportsLateFields;
+ /// For the selected lowerings, late fields and variables are encoded using
+ /// fields, getter, setters etc. in a way that provide equivalent semantics.
+ /// See `pkg/kernel/nnbd_api.md` for details.
+ int get enabledLateLowerings;
+
+ /// Returns `true` if the CFE should lower a late field given it
+ /// [hasInitializer], [isFinal], and [isStatic].
+ ///
+ /// This is determined by the [enabledLateLowerings] mask.
+ bool isLateFieldLoweringEnabled(
+ {bool hasInitializer, bool isFinal, bool isStatic}) {
+ assert(hasInitializer != null);
+ assert(isFinal != null);
+ assert(isStatic != null);
+ int mask = LateLowering.getFieldLowering(
+ hasInitializer: hasInitializer, isFinal: isFinal, isStatic: isStatic);
+ return enabledLateLowerings & mask != 0;
+ }
+
+ /// Returns `true` if the CFE should lower a late local variable given it
+ /// [hasInitializer], [isFinal], and its type [isPotentiallyNullable].
+ ///
+ /// This is determined by the [enabledLateLowerings] mask.
+ bool isLateLocalLoweringEnabled(
+ {bool hasInitializer, bool isFinal, bool isPotentiallyNullable}) {
+ assert(hasInitializer != null);
+ assert(isFinal != null);
+ assert(isPotentiallyNullable != null);
+ int mask = LateLowering.getLocalLowering(
+ hasInitializer: hasInitializer,
+ isFinal: isFinal,
+ isPotentiallyNullable: isPotentiallyNullable);
+ return enabledLateLowerings & mask != 0;
+ }
/// If `true`, the backend supports creation and checking of a sentinel value
/// for uninitialized late fields and variables through the `createSentinel`
@@ -359,7 +390,7 @@
NoneTarget(this.flags);
@override
- bool get supportsLateFields => !flags.forceLateLoweringForTesting;
+ int get enabledLateLowerings => flags.forceLateLoweringsForTesting;
@override
bool get supportsLateLoweringSentinel =>
@@ -417,3 +448,97 @@
// TODO(johnniwinther): Should this vary with the use case?
const NoneConstantsBackend(supportsUnevaluatedConstants: true);
}
+
+class LateLowering {
+ static const int nullableUninitializedNonFinalLocal = 1 << 0;
+ static const int nonNullableUninitializedNonFinalLocal = 1 << 1;
+ static const int nullableUninitializedFinalLocal = 1 << 2;
+ static const int nonNullableUninitializedFinalLocal = 1 << 3;
+ static const int nullableInitializedNonFinalLocal = 1 << 4;
+ static const int nonNullableInitializedNonFinalLocal = 1 << 5;
+ static const int nullableInitializedFinalLocal = 1 << 6;
+ static const int nonNullableInitializedFinalLocal = 1 << 7;
+ static const int uninitializedNonFinalStaticField = 1 << 8;
+ static const int uninitializedFinalStaticField = 1 << 9;
+ static const int initializedNonFinalStaticField = 1 << 10;
+ static const int initializedFinalStaticField = 1 << 11;
+ static const int uninitializedNonFinalInstanceField = 1 << 12;
+ static const int uninitializedFinalInstanceField = 1 << 13;
+ static const int initializedNonFinalInstanceField = 1 << 14;
+ static const int initializedFinalInstanceField = 1 << 15;
+
+ static const int none = 0;
+ static const int all = (1 << 16) - 1;
+
+ static int getLocalLowering(
+ {bool hasInitializer, bool isFinal, bool isPotentiallyNullable}) {
+ assert(hasInitializer != null);
+ assert(isFinal != null);
+ assert(isPotentiallyNullable != null);
+ if (hasInitializer) {
+ if (isFinal) {
+ if (isPotentiallyNullable) {
+ return nullableInitializedFinalLocal;
+ } else {
+ return nonNullableInitializedFinalLocal;
+ }
+ } else {
+ if (isPotentiallyNullable) {
+ return nullableInitializedNonFinalLocal;
+ } else {
+ return nonNullableInitializedNonFinalLocal;
+ }
+ }
+ } else {
+ if (isFinal) {
+ if (isPotentiallyNullable) {
+ return nullableUninitializedFinalLocal;
+ } else {
+ return nonNullableUninitializedFinalLocal;
+ }
+ } else {
+ if (isPotentiallyNullable) {
+ return nullableUninitializedNonFinalLocal;
+ } else {
+ return nonNullableUninitializedNonFinalLocal;
+ }
+ }
+ }
+ }
+
+ static int getFieldLowering(
+ {bool hasInitializer, bool isFinal, bool isStatic}) {
+ assert(hasInitializer != null);
+ assert(isFinal != null);
+ assert(isStatic != null);
+ if (hasInitializer) {
+ if (isFinal) {
+ if (isStatic) {
+ return initializedFinalStaticField;
+ } else {
+ return initializedFinalInstanceField;
+ }
+ } else {
+ if (isStatic) {
+ return initializedNonFinalStaticField;
+ } else {
+ return initializedNonFinalInstanceField;
+ }
+ }
+ } else {
+ if (isFinal) {
+ if (isStatic) {
+ return uninitializedFinalStaticField;
+ } else {
+ return uninitializedFinalInstanceField;
+ }
+ } else {
+ if (isStatic) {
+ return uninitializedNonFinalStaticField;
+ } else {
+ return uninitializedNonFinalInstanceField;
+ }
+ }
+ }
+ }
+}
diff --git a/pkg/kernel/lib/testing/mock_sdk_component.dart b/pkg/kernel/lib/testing/mock_sdk_component.dart
index 02ee6c8..180ad92 100644
--- a/pkg/kernel/lib/testing/mock_sdk_component.dart
+++ b/pkg/kernel/lib/testing/mock_sdk_component.dart
@@ -4,11 +4,12 @@
import 'package:kernel/ast.dart';
-/// Returns a [Component] object containing empty definitions of core SDK classes.
+/// Returns a [Component] object containing empty definitions of core SDK
+/// classes.
Component createMockSdkComponent() {
- var coreLib = new Library(Uri.parse('dart:core'), name: 'dart.core');
- var asyncLib = new Library(Uri.parse('dart:async'), name: 'dart.async');
- var internalLib =
+ Library coreLib = new Library(Uri.parse('dart:core'), name: 'dart.core');
+ Library asyncLib = new Library(Uri.parse('dart:async'), name: 'dart.async');
+ Library internalLib =
new Library(Uri.parse('dart:_internal'), name: 'dart._internal');
Class addClass(Library lib, Class c) {
@@ -16,8 +17,9 @@
return c;
}
- var objectClass = addClass(coreLib, new Class(name: 'Object'));
- var objectType = new InterfaceType(objectClass, coreLib.nonNullable);
+ Class objectClass = addClass(coreLib, new Class(name: 'Object'));
+ InterfaceType objectType =
+ new InterfaceType(objectClass, coreLib.nonNullable);
TypeParameter typeParam(String name, [DartType bound]) {
return new TypeParameter(name, bound ?? objectType);
@@ -36,12 +38,12 @@
addClass(coreLib, class_('Null'));
addClass(coreLib, class_('bool'));
- var num = addClass(coreLib, class_('num'));
+ Class num = addClass(coreLib, class_('num'));
addClass(coreLib, class_('String'));
- var iterable =
+ Class iterable =
addClass(coreLib, class_('Iterable', typeParameters: [typeParam('T')]));
{
- var T = typeParam('T');
+ TypeParameter T = typeParam('T');
addClass(
coreLib,
class_('List', typeParameters: [
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index e05a4b6..e109f0b 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -44,7 +44,7 @@
//
if (constant is InstanceConstant) {
// Avoid visiting `InstanceConstant.classReference`.
- for (final value in constant.fieldValues.values) {
+ for (final Constant value in constant.fieldValues.values) {
// Name everything in post-order visit of DAG.
getName(value);
}
@@ -76,8 +76,8 @@
final Set<String> usedNames = new Set<String>();
String disambiguate(T key1, U key2, String proposeName()) {
- getNewName() {
- var proposedName = proposeName();
+ String getNewName() {
+ String proposedName = proposeName();
if (usedNames.add(proposedName)) return proposedName;
int i = 2;
while (!usedNames.add('$proposedName$i')) {
@@ -209,13 +209,13 @@
final RegExp pathSeparator = new RegExp('[\\/]');
- nameLibraryPrefix(Library node, {String proposedName}) {
+ String nameLibraryPrefix(Library node, {String proposedName}) {
return prefixes.disambiguate(node.reference, node.reference.canonicalName,
() {
if (proposedName != null) return proposedName;
if (node.name != null) return abbreviateName(node.name);
if (node.importUri != null) {
- var path = node.importUri.hasEmptyPath
+ String path = node.importUri.hasEmptyPath
? '${node.importUri}'
: node.importUri.pathSegments.last;
if (path.endsWith('.dart')) {
@@ -233,7 +233,7 @@
if (proposedName != null) return proposedName;
CanonicalName canonicalName = name ?? node.canonicalName;
if (canonicalName?.name != null) {
- var path = canonicalName.name;
+ String path = canonicalName.name;
int slash = path.lastIndexOf(pathSeparator);
if (slash >= 0) {
path = path.substring(slash + 1);
@@ -436,14 +436,14 @@
}
void printLibraryImportTable(LibraryImportTable imports) {
- for (var library in imports.importedLibraries) {
- var importPath = imports.getImportPath(library);
+ for (Library library in imports.importedLibraries) {
+ String importPath = imports.getImportPath(library);
if (importPath == "") {
- var prefix =
+ String prefix =
syntheticNames.nameLibraryPrefix(library, proposedName: 'self');
endLine('import self as $prefix;');
} else {
- var prefix = syntheticNames.nameLibraryPrefix(library);
+ String prefix = syntheticNames.nameLibraryPrefix(library);
endLine('import "$importPath" as $prefix;');
}
}
@@ -476,7 +476,7 @@
write('additionalExports = (');
for (int i = 0; i < additionalExports.length; i++) {
Reference reference = additionalExports[i];
- var node = reference.node;
+ NamedNode node = reference.node;
if (node is Class) {
Library nodeLibrary = node.enclosingLibrary;
String prefix = syntheticNames.nameLibraryPrefix(nodeLibrary);
@@ -514,7 +514,7 @@
void writeComponentFile(Component component) {
ImportTable imports = new ComponentImportTable(component);
- var inner = createInner(imports, component.metadata);
+ Printer inner = createInner(imports, component.metadata);
writeWord('main');
writeSpaced('=');
inner.writeMemberReferenceFromReference(component.mainMethodName);
@@ -523,7 +523,7 @@
inner.writeMetadata(component);
}
writeComponentProblems(component);
- for (var library in component.libraries) {
+ for (Library library in component.libraries) {
if (showMetadata) {
inner.writeMetadata(library);
}
@@ -536,7 +536,7 @@
writeSpaced('from');
writeWord('"${library.importUri}"');
}
- var prefix = syntheticNames.nameLibraryPrefix(library);
+ String prefix = syntheticNames.nameLibraryPrefix(library);
writeSpaced('as');
writeWord(prefix);
endLine(' {');
@@ -552,7 +552,7 @@
void writeConstantTable(Component component) {
if (syntheticNames.constants.map.isEmpty) return;
ImportTable imports = new ComponentImportTable(component);
- var inner = createInner(imports, component.metadata);
+ Printer inner = createInner(imports, component.metadata);
writeWord('constants ');
endLine(' {');
++inner.indentation;
@@ -619,7 +619,7 @@
if (node == null) {
writeSymbol("<Null>");
} else {
- final highlight = shouldHighlight(node);
+ final bool highlight = shouldHighlight(node);
if (highlight) {
startHighlight(node);
}
@@ -647,8 +647,8 @@
void writeMetadata(TreeNode node) {
if (metadata != null) {
- for (var md in metadata.values) {
- final nodeMetadata = md.mapping[node];
+ for (MetadataRepository<Object> md in metadata.values) {
+ final Object nodeMetadata = md.mapping[node];
if (nodeMetadata != null) {
writeWord("[@${md.tag}=${nodeMetadata}]");
}
@@ -931,7 +931,7 @@
void writeList<T>(Iterable<T> nodes, void callback(T x),
{String separator: ','}) {
bool first = true;
- for (var node in nodes) {
+ for (T node in nodes) {
if (first) {
first = false;
} else {
@@ -948,8 +948,9 @@
String getClassReferenceFromReference(Reference reference) {
if (reference == null) return '<No Class>';
if (reference.node != null) return getClassReference(reference.asClass);
- if (reference.canonicalName != null)
+ if (reference.canonicalName != null) {
return getCanonicalNameString(reference.canonicalName);
+ }
throw "Neither node nor canonical name found";
}
@@ -960,8 +961,9 @@
String getMemberReferenceFromReference(Reference reference) {
if (reference == null) return '<No Member>';
if (reference.node != null) return getMemberReference(reference.asMember);
- if (reference.canonicalName != null)
+ if (reference.canonicalName != null) {
return getCanonicalNameString(reference.canonicalName);
+ }
throw "Neither node nor canonical name found";
}
@@ -970,8 +972,9 @@
if (name.name.startsWith('@')) throw 'unexpected @';
libraryString(CanonicalName lib) {
- if (lib.reference?.node != null)
+ if (lib.reference?.node != null) {
return getLibraryReference(lib.reference.asLibrary);
+ }
return syntheticNames.nameCanonicalNameAsLibraryPrefix(
lib.reference, lib);
}
@@ -983,7 +986,9 @@
if (name.parent.parent.isRoot) return classString(name);
CanonicalName atNode = name.parent;
- while (!atNode.name.startsWith('@')) atNode = atNode.parent;
+ while (!atNode.name.startsWith('@')) {
+ atNode = atNode.parent;
+ }
String parent = "";
if (atNode.parent.parent.isRoot) {
@@ -1001,7 +1006,7 @@
}
void writeVariableReference(VariableDeclaration variable) {
- final highlight = shouldHighlight(variable);
+ final bool highlight = shouldHighlight(variable);
if (highlight) {
startHighlight(variable);
}
@@ -1016,7 +1021,7 @@
}
void writeExpression(Expression node, [int minimumPrecedence]) {
- final highlight = shouldHighlight(node);
+ final bool highlight = shouldHighlight(node);
if (highlight) {
startHighlight(node);
}
@@ -1252,7 +1257,7 @@
if (features.isNotEmpty) {
writeSpaced('/*${features.join(',')}*/');
}
- var endLineString = ' {';
+ String endLineString = ' {';
if (node.enclosingLibrary.fileUri != node.fileUri) {
endLineString += ' // from ${node.fileUri}';
}
@@ -1274,7 +1279,7 @@
writeTypeParameterList(node.typeParameters);
writeSpaced('on');
writeType(node.onType);
- var endLineString = ' {';
+ String endLineString = ' {';
if (node.enclosingLibrary.fileUri != node.fileUri) {
endLineString += ' // from ${node.fileUri}';
}
@@ -1415,7 +1420,7 @@
writeSpace();
}
write('"');
- for (var part in node.expressions) {
+ for (Expression part in node.expressions) {
if (part is StringLiteral) {
writeSymbol(escapeString(part.value));
} else {
@@ -1677,7 +1682,7 @@
visitLibraryDependency(LibraryDependency node) {
writeIndentation();
writeWord(node.isImport ? 'import' : 'export');
- var uriString;
+ String uriString;
if (node.importedLibraryReference?.node != null) {
uriString = '${node.targetLibrary.importUri}';
} else {
@@ -1925,7 +1930,7 @@
writeIndentation();
writeWord(label);
endLine(':');
- for (var expression in node.expressions) {
+ for (Expression expression in node.expressions) {
writeIndentation();
writeWord('case');
writeExpression(expression);
@@ -2072,7 +2077,7 @@
writeSymbol('>');
}
writeSymbol('(');
- var allArgs =
+ Iterable<TreeNode> allArgs =
<List<TreeNode>>[node.positional, node.named].expand((x) => x);
writeList(allArgs, writeNode);
writeSymbol(')');
diff --git a/pkg/kernel/lib/text/serializer_combinators.dart b/pkg/kernel/lib/text/serializer_combinators.dart
index 39435d7..d25d6ae 100644
--- a/pkg/kernel/lib/text/serializer_combinators.dart
+++ b/pkg/kernel/lib/text/serializer_combinators.dart
@@ -81,8 +81,8 @@
prefix = "ID";
}
String distinctName = "$prefix$separator${nameCount++}";
- // The following checks for an internal error, not an error caused by the user.
- // So, an assert is used instead of an exception.
+ // The following checks for an internal error, not an error caused by the
+ // user. So, an assert is used instead of an exception.
assert(
lookupDistinctName(node) == null,
"Can't assign distinct name '${distinctName}' "
@@ -667,7 +667,7 @@
const Bind(this.pattern, this.term);
Tuple2<P, T> readFrom(Iterator<Object> stream, DeserializationState state) {
- var bindingState = new DeserializationState(
+ DeserializationState bindingState = new DeserializationState(
new DeserializationEnvironment(state.environment), state.nameRoot);
P first = pattern.readFrom(stream, bindingState);
bindingState.environment.extend();
@@ -677,7 +677,7 @@
void writeTo(
StringBuffer buffer, Tuple2<P, T> tuple, SerializationState state) {
- var bindingState =
+ SerializationState bindingState =
new SerializationState(new SerializationEnvironment(state.environment));
pattern.writeTo(buffer, tuple.first, bindingState);
bindingState.environment.extend();
@@ -699,7 +699,7 @@
Tuple2<P, T> readFrom(Iterator<Object> stream, DeserializationState state) {
P first = pattern1.readFrom(stream, state);
- var closedState = new DeserializationState(
+ DeserializationState closedState = new DeserializationState(
new DeserializationEnvironment(state.environment)
..binders.addAll(state.environment.binders)
..extend(),
@@ -712,7 +712,7 @@
void writeTo(
StringBuffer buffer, Tuple2<P, T> tuple, SerializationState state) {
pattern1.writeTo(buffer, tuple.first, state);
- var closedState =
+ SerializationState closedState =
new SerializationState(new SerializationEnvironment(state.environment)
..binders.addAll(state.environment.binders)
..extend());
diff --git a/pkg/kernel/lib/text/text_reader.dart b/pkg/kernel/lib/text/text_reader.dart
index e066fde..a6867e7 100644
--- a/pkg/kernel/lib/text/text_reader.dart
+++ b/pkg/kernel/lib/text/text_reader.dart
@@ -40,7 +40,7 @@
void skipToEndOfNested() {
if (current is TextIterator) {
TextIterator it = current;
- while (it.moveNext());
+ while (it.moveNext()) {}
index = it.index + 1;
}
}
diff --git a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
index 7585b5c..12901a9 100644
--- a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
+++ b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
@@ -11,8 +11,8 @@
// Parameter name used to track were widget constructor calls were made from.
//
-// The parameter name contains a randomly generated hex string to avoid collision
-// with user generated parameters.
+// The parameter name contains a randomly generated hex string to avoid
+// collision with user generated parameters.
const String _creationLocationParameterName =
r'$creationLocationd_0dea112b090073317d4';
@@ -433,11 +433,12 @@
// arguments but it is possible users could add classes with optional
// positional arguments.
//
- // constructor.initializers.add(new AssertInitializer(new AssertStatement(
- // new IsExpression(
- // new VariableGet(variable), _locationClass.thisType),
- // conditionStartOffset: constructor.fileOffset,
- // conditionEndOffset: constructor.fileOffset,
+ // constructor.initializers.add(new AssertInitializer(
+ // new AssertStatement(
+ // new IsExpression(
+ // new VariableGet(variable), _locationClass.thisType),
+ // conditionStartOffset: constructor.fileOffset,
+ // conditionEndOffset: constructor.fileOffset,
// )));
}
}
@@ -569,7 +570,8 @@
initializer: new NullLiteral());
if (_hasNamedParameter(
constructor.function, _creationLocationParameterName)) {
- // Constructor was already rewritten. TODO(jacobr): is this case actually hit?
+ // Constructor was already rewritten.
+ // TODO(jacobr): is this case actually hit?
return;
}
if (!_maybeAddNamedParameter(constructor.function, variable)) {
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index b9ca3949..4ec2480 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -34,11 +34,11 @@
Map<TypeParameter, DartType> getUpperBoundSubstitutionMap(Class host) {
if (host.typeParameters.isEmpty) return const <TypeParameter, DartType>{};
- var result = <TypeParameter, DartType>{};
- for (var parameter in host.typeParameters) {
+ Map<TypeParameter, DartType> result = <TypeParameter, DartType>{};
+ for (TypeParameter parameter in host.typeParameters) {
result[parameter] = const DynamicType();
}
- for (var parameter in host.typeParameters) {
+ for (TypeParameter parameter in host.typeParameters) {
result[parameter] = substitute(parameter.bound, result);
}
return result;
@@ -63,8 +63,8 @@
DartType substituteDeep(
DartType type, Map<TypeParameter, DartType> substitution) {
if (substitution.isEmpty) return type;
- var substitutor = new _DeepTypeSubstitutor(substitution);
- var result = substitutor.visit(type);
+ _DeepTypeSubstitutor substitutor = new _DeepTypeSubstitutor(substitution);
+ DartType result = substitutor.visit(type);
return substitutor.isInfinite ? null : result;
}
@@ -93,37 +93,16 @@
return new _FreeFunctionTypeVariableVisitor().visit(type);
}
-/// Given a set of type variables, finds a substitution of those variables such
-/// that the two given types becomes equal, or returns `null` if no such
-/// substitution exists.
-///
-/// For example, unifying `List<T>` with `List<String>`, where `T` is a
-/// quantified variable, yields the substitution `T = String`.
-///
-/// If successful, this equation holds:
-///
-/// substitute(type1, substitution) == substitute(type2, substitution)
-///
-/// The unification can fail for two reasons:
-/// - incompatible types, e.g. `List<T>` cannot be unified with `Set<T>`.
-/// - infinite types: e.g. `T` cannot be unified with `List<T>` because it
-/// would create the infinite type `List<List<List<...>>>`.
-Map<TypeParameter, DartType> unifyTypes(
- DartType type1, DartType type2, Set<TypeParameter> quantifiedVariables) {
- var unifier = new _TypeUnification(type1, type2, quantifiedVariables);
- return unifier.success ? unifier.substitution : null;
-}
-
/// Generates a fresh copy of the given type parameters, with their bounds
/// substituted to reference the new parameters.
///
/// The returned object contains the fresh type parameter list as well as a
/// mapping to be used for replacing other types to use the new type parameters.
FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) {
- var freshParameters = new List<TypeParameter>.generate(
+ List<TypeParameter> freshParameters = new List<TypeParameter>.generate(
typeParameters.length, (i) => new TypeParameter(typeParameters[i].name),
growable: true);
- var map = <TypeParameter, DartType>{};
+ Map<TypeParameter, DartType> map = <TypeParameter, DartType>{};
for (int i = 0; i < typeParameters.length; ++i) {
map[typeParameters[i]] = new TypeParameterType.forAlphaRenaming(
typeParameters[i], freshParameters[i]);
@@ -255,11 +234,11 @@
/// been replaced by dynamic.
static Substitution upperBoundForClass(Class class_) {
if (class_.typeParameters.isEmpty) return _NullSubstitution.instance;
- var upper = <TypeParameter, DartType>{};
- for (var parameter in class_.typeParameters) {
+ Map<TypeParameter, DartType> upper = <TypeParameter, DartType>{};
+ for (TypeParameter parameter in class_.typeParameters) {
upper[parameter] = const DynamicType();
}
- for (var parameter in class_.typeParameters) {
+ for (TypeParameter parameter in class_.typeParameters) {
upper[parameter] = substitute(parameter.bound, upper);
}
return fromUpperAndLowerBounds(upper, {});
@@ -483,14 +462,14 @@
Supertype visitSupertype(Supertype node) {
if (node.typeArguments.isEmpty) return node;
int before = useCounter;
- var typeArguments = node.typeArguments.map(visit).toList();
+ List<DartType> typeArguments = node.typeArguments.map(visit).toList();
if (useCounter == before) return node;
return new Supertype(node.classNode, typeArguments);
}
NamedType visitNamedType(NamedType node) {
int before = useCounter;
- var type = visit(node.type);
+ DartType type = visit(node.type);
if (useCounter == before) return node;
return new NamedType(node.name, type, isRequired: node.isRequired);
}
@@ -508,7 +487,7 @@
DartType visitInterfaceType(InterfaceType node) {
if (node.typeArguments.isEmpty) return node;
int before = useCounter;
- var typeArguments = node.typeArguments.map(visit).toList();
+ List<DartType> typeArguments = node.typeArguments.map(visit).toList();
if (useCounter == before) return node;
return new InterfaceType(node.classNode, node.nullability, typeArguments);
}
@@ -523,7 +502,7 @@
DartType visitTypedefType(TypedefType node) {
if (node.typeArguments.isEmpty) return node;
int before = useCounter;
- var typeArguments = node.typeArguments.map(visit).toList();
+ List<DartType> typeArguments = node.typeArguments.map(visit).toList();
if (useCounter == before) return node;
return new TypedefType(node.typedefNode, node.nullability, typeArguments);
}
@@ -554,19 +533,21 @@
"Function type variables cannot be substituted while still attached "
"to the function. Perform substitution on "
"`FunctionType.withoutTypeParameters` instead.");
- var inner = node.typeParameters.isEmpty ? this : newInnerEnvironment();
+ _TypeSubstitutor inner =
+ node.typeParameters.isEmpty ? this : newInnerEnvironment();
int before = this.useCounter;
// Invert the variance when translating parameters.
inner.invertVariance();
- var typeParameters = inner.freshTypeParameters(node.typeParameters);
- var positionalParameters = node.positionalParameters.isEmpty
+ List<TypeParameter> typeParameters =
+ inner.freshTypeParameters(node.typeParameters);
+ List<DartType> positionalParameters = node.positionalParameters.isEmpty
? const <DartType>[]
: node.positionalParameters.map(inner.visit).toList();
- var namedParameters = node.namedParameters.isEmpty
+ List<NamedType> namedParameters = node.namedParameters.isEmpty
? const <NamedType>[]
: node.namedParameters.map(inner.visitNamedType).toList();
inner.invertVariance();
- var returnType = inner.visit(node.returnType);
+ DartType returnType = inner.visit(node.returnType);
DartType typedefType =
node.typedefType == null ? null : inner.visit(node.typedefType);
if (this.useCounter == before) return node;
@@ -578,7 +559,7 @@
}
void bumpCountersUntil(_TypeSubstitutor target) {
- var node = this;
+ _TypeSubstitutor node = this;
while (node != target) {
++node.useCounter;
node = node.outer;
@@ -587,7 +568,7 @@
}
DartType getSubstitute(TypeParameter variable) {
- var environment = this;
+ _TypeSubstitutor environment = this;
while (environment != null) {
DartType replacement = environment.lookup(variable, covariantContext);
if (replacement != null) {
@@ -646,170 +627,6 @@
}
}
-class _TypeUnification {
- // Acyclic invariant: There are no cycles in the map, that is, all types can
- // be resolved to finite types by substituting all contained type variables.
- //
- // The acyclic invariant holds everywhere except during cycle detection.
- //
- // It is not checked that the substitution satisfies the bound on the type
- // parameter.
- final Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
-
- /// Variables that may be assigned freely in order to obtain unification.
- ///
- /// These are sometimes referred to as existentially quantified variables.
- final Set<TypeParameter> quantifiedVariables;
-
- /// Variables that are bound by a function type inside one of the types.
- /// These may not occur in a substitution, because these variables are not in
- /// scope at the existentially quantified variables.
- ///
- /// For example, suppose we are trying to satisfy the equation:
- ///
- /// ∃S. <E>(E, S) => E = <E>(E, E) => E
- ///
- /// That is, we must choose `S` such that the generic function type
- /// `<E>(E, S) => E` becomes `<E>(E, E) => E`. Choosing `S = E` is not a
- /// valid solution, because `E` is not in scope where `S` is quantified.
- /// The two function types cannot be unified.
- final Set<TypeParameter> _universallyQuantifiedVariables =
- new Set<TypeParameter>();
-
- bool success = true;
-
- _TypeUnification(DartType type1, DartType type2, this.quantifiedVariables) {
- _unify(type1, type2);
- if (success && substitution.length >= 2) {
- for (var key in substitution.keys) {
- substitution[key] = substituteDeep(substitution[key], substitution);
- }
- }
- }
-
- DartType _substituteHead(TypeParameterType type) {
- for (int i = 0; i <= substitution.length; ++i) {
- DartType nextType = substitution[type.parameter];
- if (nextType == null) return type;
- if (nextType is TypeParameterType) {
- type = nextType;
- } else {
- return nextType;
- }
- }
- // The cycle should have been found by _trySubstitution when the cycle
- // was created.
- throw 'Unexpected cycle found during unification';
- }
-
- bool _unify(DartType type1, DartType type2) {
- if (!success) return false;
- type1 = type1 is TypeParameterType ? _substituteHead(type1) : type1;
- type2 = type2 is TypeParameterType ? _substituteHead(type2) : type2;
- if (type1 is DynamicType && type2 is DynamicType) return true;
- if (type1 is VoidType && type2 is VoidType) return true;
- if (type1 is InvalidType && type2 is InvalidType) return true;
- if (type1 is BottomType && type2 is BottomType) return true;
- if (type1 is InterfaceType && type2 is InterfaceType) {
- if (type1.classNode != type2.classNode ||
- type1.nullability != type2.nullability) {
- return _fail();
- }
- assert(type1.typeArguments.length == type2.typeArguments.length);
- for (int i = 0; i < type1.typeArguments.length; ++i) {
- if (!_unify(type1.typeArguments[i], type2.typeArguments[i])) {
- return false;
- }
- }
- return true;
- }
- if (type1 is FunctionType && type2 is FunctionType) {
- if (type1.typeParameters.length != type2.typeParameters.length ||
- type1.positionalParameters.length !=
- type2.positionalParameters.length ||
- type1.namedParameters.length != type2.namedParameters.length ||
- type1.requiredParameterCount != type2.requiredParameterCount ||
- type1.nullability != type2.nullability) {
- return _fail();
- }
- // When unifying two generic functions, transform the equation like this:
- //
- // ∃S. <E>(fn1) = <T>(fn2)
- // ==>
- // ∃S. ∀G. fn1[G/E] = fn2[G/T]
- //
- // That is, assume some fixed identical choice of type parameters for both
- // functions and try to unify the instantiated function types.
- assert(!type1.typeParameters.any(quantifiedVariables.contains));
- assert(!type2.typeParameters.any(quantifiedVariables.contains));
- var leftInstance = <TypeParameter, DartType>{};
- var rightInstance = <TypeParameter, DartType>{};
- for (int i = 0; i < type1.typeParameters.length; ++i) {
- var instantiator = new TypeParameter(type1.typeParameters[i].name);
- var instantiatorType = new TypeParameterType.forAlphaRenaming(
- type1.typeParameters[i], instantiator);
- leftInstance[type1.typeParameters[i]] = instantiatorType;
- rightInstance[type2.typeParameters[i]] = instantiatorType;
- _universallyQuantifiedVariables.add(instantiator);
- }
- for (int i = 0; i < type1.typeParameters.length; ++i) {
- var left = substitute(type1.typeParameters[i].bound, leftInstance);
- var right = substitute(type2.typeParameters[i].bound, rightInstance);
- if (!_unify(left, right)) return false;
- }
- for (int i = 0; i < type1.positionalParameters.length; ++i) {
- var left = substitute(type1.positionalParameters[i], leftInstance);
- var right = substitute(type2.positionalParameters[i], rightInstance);
- if (!_unify(left, right)) return false;
- }
- for (int i = 0; i < type1.namedParameters.length; ++i) {
- if (type1.namedParameters[i].name != type2.namedParameters[i].name) {
- return false;
- }
- var left = substitute(type1.namedParameters[i].type, leftInstance);
- var right = substitute(type2.namedParameters[i].type, rightInstance);
- if (!_unify(left, right)) return false;
- }
- var leftReturn = substitute(type1.returnType, leftInstance);
- var rightReturn = substitute(type2.returnType, rightInstance);
- if (!_unify(leftReturn, rightReturn)) return false;
- return true;
- }
- if (type1 is TypeParameterType &&
- type2 is TypeParameterType &&
- type1.parameter == type2.parameter &&
- type1.declaredNullability == type2.declaredNullability) {
- return true;
- }
- if (type1 is TypeParameterType &&
- quantifiedVariables.contains(type1.parameter)) {
- return _trySubstitution(type1.parameter, type2);
- }
- if (type2 is TypeParameterType &&
- quantifiedVariables.contains(type2.parameter)) {
- return _trySubstitution(type2.parameter, type1);
- }
- return _fail();
- }
-
- bool _trySubstitution(TypeParameter variable, DartType type) {
- if (containsTypeVariable(type, _universallyQuantifiedVariables)) {
- return _fail();
- }
- // Set the plain substitution first and then generate the deep
- // substitution to detect cycles.
- substitution[variable] = type;
- DartType deepSubstitute = substituteDeep(type, substitution);
- if (deepSubstitute == null) return _fail();
- substitution[variable] = deepSubstitute;
- return true;
- }
-
- bool _fail() {
- return success = false;
- }
-}
-
class _OccurrenceVisitor implements DartTypeVisitor<bool> {
final Set<TypeParameter> variables;
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 2106e8e..1b79258 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -25,37 +25,38 @@
: environment = new TypeEnvironment(coreTypes, hierarchy);
void checkComponent(Component component) {
- for (var library in component.libraries) {
+ for (Library library in component.libraries) {
if (ignoreSdk && library.importUri.scheme == 'dart') continue;
- for (var class_ in library.classes) {
+ for (Class class_ in library.classes) {
hierarchy.forEachOverridePair(class_,
(Member ownMember, Member superMember, bool isSetter) {
checkOverride(class_, ownMember, superMember, isSetter);
});
}
}
- var visitor = new TypeCheckingVisitor(this, environment, hierarchy);
- for (var library in component.libraries) {
+ TypeCheckingVisitor visitor =
+ new TypeCheckingVisitor(this, environment, hierarchy);
+ for (Library library in component.libraries) {
currentLibrary = library;
if (ignoreSdk && library.importUri.scheme == 'dart') continue;
- for (var class_ in library.classes) {
+ for (Class class_ in library.classes) {
currentThisType = coreTypes.thisInterfaceType(
class_, class_.enclosingLibrary.nonNullable);
- for (var field in class_.fields) {
+ for (Field field in class_.fields) {
visitor.visitField(field);
}
- for (var constructor in class_.constructors) {
+ for (Constructor constructor in class_.constructors) {
visitor.visitConstructor(constructor);
}
- for (var procedure in class_.procedures) {
+ for (Procedure procedure in class_.procedures) {
visitor.visitProcedure(procedure);
}
}
currentThisType = null;
- for (var procedure in library.procedures) {
+ for (Procedure procedure in library.procedures) {
visitor.visitProcedure(procedure);
}
- for (var field in library.fields) {
+ for (Field field in library.fields) {
visitor.visitField(field);
}
currentLibrary = null;
@@ -63,14 +64,16 @@
}
DartType getterType(Class host, Member member) {
- var hostType = hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
- var substitution = Substitution.fromSupertype(hostType);
+ Supertype hostType =
+ hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
+ Substitution substitution = Substitution.fromSupertype(hostType);
return substitution.substituteType(member.getterType);
}
DartType setterType(Class host, Member member) {
- var hostType = hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
- var substitution = Substitution.fromSupertype(hostType);
+ Supertype hostType =
+ hierarchy.getClassAsInstanceOf(host, member.enclosingClass);
+ Substitution substitution = Substitution.fromSupertype(hostType);
return substitution.substituteType(member.setterType, contravariant: true);
}
@@ -141,9 +144,9 @@
}
Expression checkAndDowncastExpression(Expression from, DartType to) {
- var parent = from.parent;
- var type = visitExpression(from);
- var result = checker.checkAndDowncastExpression(from, type, to);
+ TreeNode parent = from.parent;
+ DartType type = visitExpression(from);
+ Expression result = checker.checkAndDowncastExpression(from, type, to);
result.parent = parent;
return result;
}
@@ -210,7 +213,7 @@
}
void handleFunctionNode(FunctionNode node) {
- var oldAsyncMarker = currentAsyncMarker;
+ AsyncMarker oldAsyncMarker = currentAsyncMarker;
currentAsyncMarker = node.asyncMarker;
node.positionalParameters
.skip(node.requiredParameterCount)
@@ -223,8 +226,8 @@
}
void handleNestedFunctionNode(FunctionNode node) {
- var oldReturn = currentReturnType;
- var oldYield = currentYieldType;
+ DartType oldReturn = currentReturnType;
+ DartType oldYield = currentYieldType;
currentReturnType = _getInternalReturnType(node);
currentYieldType = _getYieldType(node);
handleFunctionNode(node);
@@ -241,7 +244,7 @@
Substitution getReceiverType(
TreeNode access, Expression receiver, Member member) {
- var type = visitExpression(receiver);
+ DartType type = visitExpression(receiver);
Class superclass = member.enclosingClass;
if (superclass.supertype == null) {
return Substitution.empty; // Members on Object are always accessible.
@@ -291,7 +294,7 @@
fail(arguments, 'Too many positional arguments');
return const BottomType();
}
- var typeArguments = arguments.types;
+ List<DartType> typeArguments = arguments.types;
if (typeArguments.length != typeParameters.length) {
fail(arguments, 'Wrong number of type arguments');
return const BottomType();
@@ -300,18 +303,18 @@
typeParameters, typeArguments, arguments,
receiverSubstitution: receiver);
for (int i = 0; i < arguments.positional.length; ++i) {
- var expectedType = substitution.substituteType(
+ DartType expectedType = substitution.substituteType(
functionType.positionalParameters[i],
contravariant: true);
arguments.positional[i] =
checkAndDowncastExpression(arguments.positional[i], expectedType);
}
for (int i = 0; i < arguments.named.length; ++i) {
- var argument = arguments.named[i];
+ NamedExpression argument = arguments.named[i];
bool found = false;
for (int j = 0; j < functionType.namedParameters.length; ++j) {
if (argument.name == functionType.namedParameters[j].name) {
- var expectedType = substitution.substituteType(
+ DartType expectedType = substitution.substituteType(
functionType.namedParameters[j].type,
contravariant: true);
argument.value =
@@ -357,7 +360,7 @@
while (parent is! FunctionNode) {
parent = parent.parent;
}
- var enclosingFunction = parent as FunctionNode;
+ FunctionNode enclosingFunction = parent as FunctionNode;
if (enclosingFunction.dartAsyncMarker == AsyncMarker.Sync) {
parent = enclosingFunction.parent;
while (parent is! FunctionNode) {
@@ -403,13 +406,14 @@
Substitution _instantiateFunction(List<TypeParameter> typeParameters,
List<DartType> typeArguments, TreeNode where,
{Substitution receiverSubstitution}) {
- var instantiation = Substitution.fromPairs(typeParameters, typeArguments);
- var substitution = receiverSubstitution == null
+ Substitution instantiation =
+ Substitution.fromPairs(typeParameters, typeArguments);
+ Substitution substitution = receiverSubstitution == null
? instantiation
: Substitution.combine(receiverSubstitution, instantiation);
for (int i = 0; i < typeParameters.length; ++i) {
- var argument = typeArguments[i];
- var bound = substitution.substituteType(typeParameters[i].bound);
+ DartType argument = typeArguments[i];
+ DartType bound = substitution.substituteType(typeParameters[i].bound);
checkAssignable(where, argument, bound);
}
return substitution;
@@ -484,7 +488,7 @@
@override
DartType visitLet(Let node) {
- var value = visitExpression(node.variable.initializer);
+ DartType value = visitExpression(node.variable.initializer);
if (node.variable.type is DynamicType) {
node.variable.type = value;
}
@@ -543,7 +547,7 @@
@override
DartType visitMapLiteral(MapLiteral node) {
- for (var entry in node.entries) {
+ for (MapEntry entry in node.entries) {
entry.key = checkAndDowncastExpression(entry.key, node.keyType);
entry.value = checkAndDowncastExpression(entry.value, node.valueType);
}
@@ -571,20 +575,20 @@
fail(access, 'Wrong number of type arguments');
return const BottomType();
}
- var instantiation =
+ Substitution instantiation =
Substitution.fromPairs(function.typeParameters, arguments.types);
for (int i = 0; i < arguments.positional.length; ++i) {
- var expectedType = instantiation.substituteType(
+ DartType expectedType = instantiation.substituteType(
function.positionalParameters[i],
contravariant: true);
arguments.positional[i] =
checkAndDowncastExpression(arguments.positional[i], expectedType);
}
for (int i = 0; i < arguments.named.length; ++i) {
- var argument = arguments.named[i];
- var parameterType = function.getNamedParameter(argument.name);
+ NamedExpression argument = arguments.named[i];
+ DartType parameterType = function.getNamedParameter(argument.name);
if (parameterType != null) {
- var expectedType =
+ DartType expectedType =
instantiation.substituteType(parameterType, contravariant: true);
argument.value =
checkAndDowncastExpression(argument.value, expectedType);
@@ -598,9 +602,9 @@
@override
DartType visitMethodInvocation(MethodInvocation node) {
- var target = node.interfaceTarget;
+ Member target = node.interfaceTarget;
if (target == null) {
- var receiver = visitExpression(node.receiver);
+ DartType receiver = visitExpression(node.receiver);
if (node.name.text == '==') {
visitExpression(node.arguments.positional.single);
return environment.coreTypes.boolLegacyRawType;
@@ -613,8 +617,8 @@
} else if (target is Procedure &&
environment.isSpecialCasedBinaryOperator(target)) {
assert(node.arguments.positional.length == 1);
- var receiver = visitExpression(node.receiver);
- var argument = visitExpression(node.arguments.positional[0]);
+ DartType receiver = visitExpression(node.receiver);
+ DartType argument = visitExpression(node.arguments.positional[0]);
return environment.getTypeOfSpecialCasedBinaryOperator(
receiver, argument);
} else {
@@ -626,27 +630,29 @@
@override
DartType visitPropertyGet(PropertyGet node) {
if (node.interfaceTarget == null) {
- final receiver = visitExpression(node.receiver);
+ final DartType receiver = visitExpression(node.receiver);
checkUnresolvedInvocation(receiver, node);
return const DynamicType();
} else {
- var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
+ Substitution receiver =
+ getReceiverType(node, node.receiver, node.interfaceTarget);
return receiver.substituteType(node.interfaceTarget.getterType);
}
}
@override
DartType visitPropertySet(PropertySet node) {
- var value = visitExpression(node.value);
+ DartType value = visitExpression(node.value);
if (node.interfaceTarget != null) {
- var receiver = getReceiverType(node, node.receiver, node.interfaceTarget);
+ Substitution receiver =
+ getReceiverType(node, node.receiver, node.interfaceTarget);
checkAssignable(
node.value,
value,
receiver.substituteType(node.interfaceTarget.setterType,
contravariant: true));
} else {
- final receiver = visitExpression(node.receiver);
+ final DartType receiver = visitExpression(node.receiver);
checkUnresolvedInvocation(receiver, node);
}
return value;
@@ -686,7 +692,7 @@
@override
DartType visitStaticSet(StaticSet node) {
- var value = visitExpression(node.value);
+ DartType value = visitExpression(node.value);
checkAssignable(node.value, value, node.target.setterType);
return value;
}
@@ -770,16 +776,16 @@
checkUnresolvedInvocation(currentThisType, node);
return const DynamicType();
} else {
- var receiver = getSuperReceiverType(node.interfaceTarget);
+ Substitution receiver = getSuperReceiverType(node.interfaceTarget);
return receiver.substituteType(node.interfaceTarget.getterType);
}
}
@override
DartType visitSuperPropertySet(SuperPropertySet node) {
- var value = visitExpression(node.value);
+ DartType value = visitExpression(node.value);
if (node.interfaceTarget != null) {
- var receiver = getSuperReceiverType(node.interfaceTarget);
+ Substitution receiver = getSuperReceiverType(node.interfaceTarget);
checkAssignable(
node.value,
value,
@@ -819,7 +825,7 @@
@override
DartType visitVariableSet(VariableSet node) {
- var value = visitExpression(node.value);
+ DartType value = visitExpression(node.value);
checkAssignable(node.value, value, node.variable.type);
return value;
}
@@ -881,7 +887,7 @@
@override
visitForInStatement(ForInStatement node) {
- var iterable = visitExpression(node.iterable);
+ DartType iterable = visitExpression(node.iterable);
// TODO(asgerf): Store interface targets on for-in loops or desugar them,
// instead of doing the ad-hoc resolution here.
if (node.isAsync) {
@@ -898,7 +904,7 @@
DartType getIterableElementType(DartType iterable) {
if (iterable is InterfaceType) {
- var iteratorGetter =
+ Member iteratorGetter =
hierarchy.getInterfaceMember(iterable.classNode, iteratorName);
if (iteratorGetter == null) return const DynamicType();
List<DartType> castedIterableArguments =
@@ -909,7 +915,7 @@
castedIterableArguments)
.substituteType(iteratorGetter.getterType);
if (iteratorType is InterfaceType) {
- var currentGetter =
+ Member currentGetter =
hierarchy.getInterfaceMember(iteratorType.classNode, currentName);
if (currentGetter == null) return const DynamicType();
List<DartType> castedIteratorTypeArguments =
@@ -971,7 +977,7 @@
if (currentReturnType == null) {
fail(node, 'Return of a value from void method');
} else {
- var type = visitExpression(node.expression);
+ DartType type = visitExpression(node.expression);
if (currentAsyncMarker == AsyncMarker.Async) {
type = environment.flatten(type);
}
@@ -983,7 +989,7 @@
@override
visitSwitchStatement(SwitchStatement node) {
visitExpression(node.expression);
- for (var switchCase in node.cases) {
+ for (SwitchCase switchCase in node.cases) {
switchCase.expressions.forEach(visitExpression);
visitStatement(switchCase.body);
}
@@ -992,7 +998,7 @@
@override
visitTryCatch(TryCatch node) {
visitStatement(node.body);
- for (var catchClause in node.catches) {
+ for (Catch catchClause in node.catches) {
visitStatement(catchClause.body);
}
}
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 3ab077d..cc2d51b 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -119,7 +119,7 @@
" but found: '${node.parent.runtimeType}'.",
context: currentParent);
}
- var oldParent = currentParent;
+ TreeNode oldParent = currentParent;
currentParent = node;
return oldParent;
}
@@ -138,7 +138,7 @@
}
void visitChildren(TreeNode node) {
- var oldParent = enterParent(node);
+ TreeNode oldParent = enterParent(node);
node.visitChildren(this);
exitParent(oldParent);
}
@@ -175,7 +175,7 @@
void declareTypeParameters(List<TypeParameter> parameters) {
for (int i = 0; i < parameters.length; ++i) {
- var parameter = parameters[i];
+ TypeParameter parameter = parameters[i];
if (parameter.bound == null) {
problem(
currentParent, "Missing bound for type parameter '$parameter'.");
@@ -202,27 +202,27 @@
visitComponent(Component component) {
try {
- for (var library in component.libraries) {
- for (var class_ in library.classes) {
+ for (Library library in component.libraries) {
+ for (Class class_ in library.classes) {
if (!classes.add(class_)) {
problem(class_, "Class '$class_' declared more than once.");
}
}
- for (var typedef_ in library.typedefs) {
+ for (Typedef typedef_ in library.typedefs) {
if (!typedefs.add(typedef_)) {
problem(typedef_, "Typedef '$typedef_' declared more than once.");
}
}
library.members.forEach(declareMember);
- for (var class_ in library.classes) {
+ for (Class class_ in library.classes) {
class_.members.forEach(declareMember);
}
}
visitChildren(component);
} finally {
- for (var library in component.libraries) {
+ for (Library library in component.libraries) {
library.members.forEach(undeclareMember);
- for (var class_ in library.classes) {
+ for (Class class_ in library.classes) {
class_.members.forEach(undeclareMember);
}
}
@@ -238,23 +238,23 @@
visitExtension(Extension node) {
declareTypeParameters(node.typeParameters);
- final oldParent = enterParent(node);
+ final TreeNode oldParent = enterParent(node);
node.visitChildren(this);
exitParent(oldParent);
undeclareTypeParameters(node.typeParameters);
}
void checkTypedef(Typedef node) {
- var state = typedefState[node];
+ TypedefState state = typedefState[node];
if (state == TypedefState.Done) return;
if (state == TypedefState.BeingChecked) {
problem(node, "The typedef '$node' refers to itself", context: node);
}
assert(state == null);
typedefState[node] = TypedefState.BeingChecked;
- var savedTypeParameters = typeParametersInScope;
+ Set<TypeParameter> savedTypeParameters = typeParametersInScope;
typeParametersInScope = node.typeParameters.toSet();
- var savedParent = currentParent;
+ TreeNode savedParent = currentParent;
currentParent = node;
// Visit children without checking the parent pointer on the typedef itself
// since this can be called from a context other than its true parent.
@@ -272,7 +272,7 @@
visitField(Field node) {
currentMember = node;
- var oldParent = enterParent(node);
+ TreeNode oldParent = enterParent(node);
bool isTopLevel = node.parent == currentLibrary;
if (isTopLevel && !node.isStatic) {
problem(node, "The top-level field '${node.name.text}' should be static",
@@ -293,7 +293,7 @@
visitProcedure(Procedure node) {
currentMember = node;
- var oldParent = enterParent(node);
+ TreeNode oldParent = enterParent(node);
classTypeParametersAreInScope = !node.isStatic;
if (node.isAbstract && node.isExternal) {
problem(node, "Procedure cannot be both abstract and external.");
@@ -346,7 +346,7 @@
classTypeParametersAreInScope = true;
// The constructor member needs special treatment due to parameters being
// in scope in the initializer list.
- var oldParent = enterParent(node);
+ TreeNode oldParent = enterParent(node);
int stackHeight = enterLocalScope();
visitChildren(node.function);
visitList(node.initializers, this);
@@ -364,7 +364,7 @@
visitClass(Class node) {
currentClass = node;
declareTypeParameters(node.typeParameters);
- var oldParent = enterParent(node);
+ TreeNode oldParent = enterParent(node);
classTypeParametersAreInScope = false;
visitList(node.annotations, this);
classTypeParametersAreInScope = true;
@@ -397,7 +397,7 @@
}
}
declareTypeParameters(node.typeParameters);
- for (var typeParameter in node.typeParameters) {
+ for (TypeParameter typeParameter in node.typeParameters) {
typeParameter.bound?.accept(this);
if (typeParameter.annotations.isNotEmpty) {
problem(
@@ -458,8 +458,10 @@
break;
case AsyncMarker.SyncStar:
case AsyncMarker.AsyncStar:
- problem(node,
- "Return statement in function with async marker: $currentAsyncMarker");
+ problem(
+ node,
+ "Return statement in function with async marker: "
+ "$currentAsyncMarker");
break;
}
super.visitReturnStatement(node);
@@ -470,8 +472,10 @@
switch (currentAsyncMarker) {
case AsyncMarker.Sync:
case AsyncMarker.Async:
- problem(node,
- "Yield statement in function with async marker: $currentAsyncMarker");
+ problem(
+ node,
+ "Yield statement in function with async marker: "
+ "$currentAsyncMarker");
break;
case AsyncMarker.SyncStar:
case AsyncMarker.AsyncStar:
@@ -490,7 +494,7 @@
}
visitVariableDeclaration(VariableDeclaration node) {
- var parent = node.parent;
+ TreeNode parent = node.parent;
if (parent is! Block &&
!(parent is Catch && parent.body != node) &&
!(parent is FunctionNode && parent.body != node) &&
@@ -638,7 +642,7 @@
}
namedLoop:
for (int i = 0; i < arguments.named.length; ++i) {
- var argument = arguments.named[i];
+ NamedExpression argument = arguments.named[i];
String name = argument.name;
for (int j = 0; j < function.namedParameters.length; ++j) {
if (function.namedParameters[j].name == name) continue namedLoop;
@@ -771,7 +775,7 @@
@override
visitTypeParameterType(TypeParameterType node) {
- var parameter = node.parameter;
+ TypeParameter parameter = node.parameter;
if (!typeParametersInScope.contains(parameter)) {
problem(
currentParent,
@@ -904,7 +908,7 @@
"is '${node.parent.runtimeType}' "
"but should be '${parent.runtimeType}'.");
}
- var oldParent = parent;
+ TreeNode oldParent = parent;
parent = node;
node.visitChildren(this);
parent = oldParent;
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index 1fec5a3..fdabdc6 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -414,7 +414,8 @@
/// Visits [node] if not already visited to compute a value for [node].
///
- /// If the value has already been computed the cached value is returned immediately.
+ /// If the value has already been computed the cached value is returned
+ /// immediately.
///
/// Call this method to compute values for subnodes recursively, while only
/// visiting each subnode once.
diff --git a/pkg/kernel/lib/vm/constants_native_effects.dart b/pkg/kernel/lib/vm/constants_native_effects.dart
index fb52988..67b436b 100644
--- a/pkg/kernel/lib/vm/constants_native_effects.dart
+++ b/pkg/kernel/lib/vm/constants_native_effects.dart
@@ -38,7 +38,8 @@
}
// This is a bit fishy, since we merge the key and the value type by
// putting both into the same list.
- final kvListConstant = new ListConstant(const DynamicType(), kvListPairs);
+ final ListConstant kvListConstant =
+ new ListConstant(const DynamicType(), kvListPairs);
assert(immutableMapClass.fields.length == 1);
final Field kvPairListField = immutableMapClass.fields[0];
return new InstanceConstant(immutableMapClass.reference, <DartType>[
diff --git a/pkg/kernel/test/class_hierarchy_test.dart b/pkg/kernel/test/class_hierarchy_test.dart
index bd0ad7a..bf078f8 100644
--- a/pkg/kernel/test/class_hierarchy_test.dart
+++ b/pkg/kernel/test/class_hierarchy_test.dart
@@ -453,7 +453,8 @@
''');
// The documentation says:
- // It is possible for two methods to override one another in both directions.
+ // It is possible for two methods to override one another in both
+ // directions.
_assertOverridePairs(b, ['test::B.foo overrides test::A.foo']);
}
@@ -1227,12 +1228,12 @@
void callback(
Member declaredMember, Member interfaceMember, bool isSetter) {
var suffix = isSetter ? '=' : '';
- String declaredName =
- '${qualifiedMemberNameToString(declaredMember, includeLibraryName: true)}'
- '$suffix';
- String interfaceName =
- '${qualifiedMemberNameToString(interfaceMember, includeLibraryName: true)}'
- '$suffix';
+ String declaredMemberName =
+ qualifiedMemberNameToString(declaredMember, includeLibraryName: true);
+ String declaredName = '${declaredMemberName}$suffix';
+ String interfaceMemberName = qualifiedMemberNameToString(interfaceMember,
+ includeLibraryName: true);
+ String interfaceName = '${interfaceMemberName}$suffix';
var desc = '$declaredName overrides $interfaceName';
overrideDescriptions.add(desc);
}
diff --git a/pkg/kernel/test/non_null_test.dart b/pkg/kernel/test/non_null_test.dart
index 77750c8..542cc09 100644
--- a/pkg/kernel/test/non_null_test.dart
+++ b/pkg/kernel/test/non_null_test.dart
@@ -40,13 +40,18 @@
'FutureOr<Object*>*': 'FutureOr<Object>',
'FutureOr<FutureOr<Object?>>': 'FutureOr<FutureOr<Object>>',
'(List<Object>, {required List<Object> a, List<Object> b}) -> List<Object>':
- '(List<Object>, {required List<Object> a, List<Object> b}) -> List<Object>',
+ '(List<Object>, {required List<Object> a, List<Object> b})'
+ ' -> List<Object>',
'(List<Object>, {required List<Object> a, List<Object> b}) ->? List<Object>':
- '(List<Object>, {required List<Object> a, List<Object> b}) -> List<Object>',
+ '(List<Object>, {required List<Object> a, List<Object> b})'
+ ' -> List<Object>',
'(List<Object>, {required List<Object> a, List<Object> b}) ->* List<Object>':
- '(List<Object>, {required List<Object> a, List<Object> b}) -> List<Object>',
- '(List<Object>?, {required List<Object?> a, List<Object?>? b}) ->? List<Object?>':
- '(List<Object>?, {required List<Object?> a, List<Object?>? b}) -> List<Object?>',
+ '(List<Object>, {required List<Object> a, List<Object> b})'
+ ' -> List<Object>',
+ '(List<Object>?, {required List<Object?> a, List<Object?>? b})'
+ ' ->? List<Object?>':
+ '(List<Object>?, {required List<Object?> a, List<Object?>? b})'
+ ' -> List<Object?>',
'X': 'X & Object',
'X?': 'X & Object',
'X*': 'X & Object',
diff --git a/pkg/kernel/test/text_serializer_test.dart b/pkg/kernel/test/text_serializer_test.dart
index f4b3631..521aca4 100644
--- a/pkg/kernel/test/text_serializer_test.dart
+++ b/pkg/kernel/test/text_serializer_test.dart
@@ -83,8 +83,8 @@
test('(const-list (dynamic) ((int 0) (int 1) (int 2)))');
test('(set (dynamic) ((bool true) (bool false) (int 0)))');
test('(const-set (dynamic) ((int 0) (int 1) (int 2)))');
- test(
- '(map (dynamic) (void) ((int 0) (null) (int 1) (null) (int 2) (null)))');
+ test('(map (dynamic) (void)'
+ ' ((int 0) (null) (int 1) (null) (int 2) (null)))');
test('(const-map (dynamic) (void) ((int 0) (null) (int 1) (null) '
'(int 2) (null)))');
test('(type (-> () () () ((dynamic)) () () (dynamic)))');
diff --git a/pkg/kernel/test/type_hashcode_test.dart b/pkg/kernel/test/type_hashcode_test.dart
index 468deb6..b988507 100644
--- a/pkg/kernel/test/type_hashcode_test.dart
+++ b/pkg/kernel/test/type_hashcode_test.dart
@@ -3,9 +3,79 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/kernel.dart';
import 'type_parser.dart';
-import 'type_unification_test.dart' show testCases;
import 'package:test/test.dart';
+final List<TestCase> testCases = <TestCase>[
+ successCase('List<T>', 'List<String>', {'T': 'String'}),
+ successCase('List<String>', 'List<T>', {'T': 'String'}),
+ successCase('List<T>', 'List<T>', {'T': null}),
+ successCase('List<S>', 'List<T>', {'S': 'T'}),
+ successCase('List<S>', 'List<T>', {'T': 'S'}),
+ successCase(
+ 'List<S>', 'List<T>', {'S': 'T', 'T': null}), // Require left bias.
+ failureCase('List<S>', 'List<T>', []),
+
+ failureCase('List<T>', 'T', ['T']),
+ failureCase('List<List<T>>', 'List<T>', ['T']),
+ failureCase('Map<S, T>', 'Map<List<T>, List<S>>', ['T', 'S']),
+
+ failureCase('Map<Map<S,String>, Map<int,S>>',
+ 'Map<Map<int, S>, Map<S, String>>', ['S']),
+ successCase('Map<Map<S, int>, Map<int, S>>', 'Map<Map<int, S>, Map<S, int>>',
+ {'S': 'int'}),
+ successCase('Map<Map<S, String>, Map<int, T>>',
+ 'Map<Map<int, T>, Map<S, String>>', {'S': 'int', 'T': 'String'}),
+
+ successCase('Map<S, List<T>>', 'Map<T, List<S>>', {'S': 'T'}),
+ successCase('Map<S, T>', 'Map<S, List<S>>', {'T': 'List<S>'}),
+ successCase('Map<S, T>', 'Map<S, List<S>>', {'T': 'List<S>', 'S': null}),
+ successCase('Map<List<S>, T>', 'Map<T, List<S>>', {'T': 'List<S>'}),
+ successCase(
+ 'Map<List<S>, T>', 'Map<T, List<S>>', {'T': 'List<S>', 'S': null}),
+
+ successCase('<E>(E) => E', '<T>(T) => T', {}),
+ successCase('<E>(E, S) => E', '<T>(T, int) => T', {'S': 'int'}),
+ failureCase('<E>(E, S) => E', '<T>(T, T) => T', ['S']),
+ successCase(
+ '<E>(E) => <T>(T) => Map<E,T>', '<E>(E) => <T>(T) => Map<E,T>', {}),
+ successCase('<E>(E,_) => E', '<T>(T,_) => T', {}),
+
+ successCase('(x:int,y:String) => int', '(y:String,x:int) => int', {}),
+ successCase('<S,T>(x:S,y:T) => S', '<S,T>(y:T,x:S) => S', {}),
+ successCase('(x:<T>(T)=>T,y:<S>(S)=>S) => int',
+ '(y:<S>(S)=>S,x:<T>(T)=>T) => int', {}),
+ successCase('(x:<T>(T)=>T,y:<S>(S,S,S)=>S) => int',
+ '(y:<S>(S,S,S)=>S,x:<T>(T)=>T) => int', {}),
+];
+
+class TestCase {
+ String type1;
+ String type2;
+ Iterable<String> quantifiedVariables;
+ Map<String, String> expectedSubstitution; // Null if unification should fail.
+
+ TestCase.success(this.type1, this.type2, this.expectedSubstitution) {
+ quantifiedVariables = expectedSubstitution.keys;
+ }
+
+ TestCase.fail(this.type1, this.type2, this.quantifiedVariables);
+
+ bool get shouldSucceed => expectedSubstitution != null;
+
+ String toString() => '∃ ${quantifiedVariables.join(',')}. $type1 = $type2';
+}
+
+TestCase successCase(String type1, String type2, Map<String, String> expected,
+ {bool debug: false}) {
+ return new TestCase.success(type1, type2, expected);
+}
+
+TestCase failureCase(
+ String type1, String type2, List<String> quantifiedVariables,
+ {bool debug: false}) {
+ return new TestCase.fail(type1, type2, quantifiedVariables);
+}
+
void checkHashCodeEquality(DartType type1, DartType type2) {
if (type1 == type2 && type1.hashCode != type2.hashCode) {
fail('Equal types with different hash codes: $type1 and $type2');
diff --git a/pkg/kernel/test/type_substitution_identity_test.dart b/pkg/kernel/test/type_substitution_identity_test.dart
index d07da2a..d8fabbd 100644
--- a/pkg/kernel/test/type_substitution_identity_test.dart
+++ b/pkg/kernel/test/type_substitution_identity_test.dart
@@ -1,10 +1,11 @@
// 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.
+
import 'package:kernel/kernel.dart';
import 'package:kernel/type_algebra.dart';
import 'type_parser.dart';
-import 'type_unification_test.dart' show testCases;
+import 'type_hashcode_test.dart' show testCases;
import 'package:test/test.dart';
checkType(DartType type) {
diff --git a/pkg/kernel/test/type_unification_test.dart b/pkg/kernel/test/type_unification_test.dart
deleted file mode 100644
index 2e79fdb..0000000
--- a/pkg/kernel/test/type_unification_test.dart
+++ /dev/null
@@ -1,140 +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.
-import 'package:kernel/type_algebra.dart';
-import 'package:test/test.dart';
-import 'type_parser.dart';
-import 'dart:io';
-
-final List<TestCase> testCases = <TestCase>[
- successCase('List<T>', 'List<String>', {'T': 'String'}),
- successCase('List<String>', 'List<T>', {'T': 'String'}),
- successCase('List<T>', 'List<T>', {'T': null}),
- successCase('List<S>', 'List<T>', {'S': 'T'}),
- successCase('List<S>', 'List<T>', {'T': 'S'}),
- successCase(
- 'List<S>', 'List<T>', {'S': 'T', 'T': null}), // Require left bias.
- failureCase('List<S>', 'List<T>', []),
-
- failureCase('List<T>', 'T', ['T']),
- failureCase('List<List<T>>', 'List<T>', ['T']),
- failureCase('Map<S, T>', 'Map<List<T>, List<S>>', ['T', 'S']),
-
- failureCase('Map<Map<S,String>, Map<int,S>>',
- 'Map<Map<int, S>, Map<S, String>>', ['S']),
- successCase('Map<Map<S, int>, Map<int, S>>', 'Map<Map<int, S>, Map<S, int>>',
- {'S': 'int'}),
- successCase('Map<Map<S, String>, Map<int, T>>',
- 'Map<Map<int, T>, Map<S, String>>', {'S': 'int', 'T': 'String'}),
-
- successCase('Map<S, List<T>>', 'Map<T, List<S>>', {'S': 'T'}),
- successCase('Map<S, T>', 'Map<S, List<S>>', {'T': 'List<S>'}),
- successCase('Map<S, T>', 'Map<S, List<S>>', {'T': 'List<S>', 'S': null}),
- successCase('Map<List<S>, T>', 'Map<T, List<S>>', {'T': 'List<S>'}),
- successCase(
- 'Map<List<S>, T>', 'Map<T, List<S>>', {'T': 'List<S>', 'S': null}),
-
- successCase('<E>(E) => E', '<T>(T) => T', {}),
- successCase('<E>(E, S) => E', '<T>(T, int) => T', {'S': 'int'}),
- failureCase('<E>(E, S) => E', '<T>(T, T) => T', ['S']),
- successCase(
- '<E>(E) => <T>(T) => Map<E,T>', '<E>(E) => <T>(T) => Map<E,T>', {}),
- successCase('<E>(E,_) => E', '<T>(T,_) => T', {}),
-
- successCase('(x:int,y:String) => int', '(y:String,x:int) => int', {}),
- successCase('<S,T>(x:S,y:T) => S', '<S,T>(y:T,x:S) => S', {}),
- successCase('(x:<T>(T)=>T,y:<S>(S)=>S) => int',
- '(y:<S>(S)=>S,x:<T>(T)=>T) => int', {}),
- successCase('(x:<T>(T)=>T,y:<S>(S,S,S)=>S) => int',
- '(y:<S>(S,S,S)=>S,x:<T>(T)=>T) => int', {}),
-];
-
-class TestCase {
- String type1;
- String type2;
- Iterable<String> quantifiedVariables;
- Map<String, String> expectedSubstitution; // Null if unification should fail.
-
- TestCase.success(this.type1, this.type2, this.expectedSubstitution) {
- quantifiedVariables = expectedSubstitution.keys;
- }
-
- TestCase.fail(this.type1, this.type2, this.quantifiedVariables);
-
- bool get shouldSucceed => expectedSubstitution != null;
-
- String toString() => '∃ ${quantifiedVariables.join(',')}. $type1 = $type2';
-}
-
-TestCase successCase(String type1, String type2, Map<String, String> expected,
- {bool debug: false}) {
- return new TestCase.success(type1, type2, expected);
-}
-
-TestCase failureCase(
- String type1, String type2, List<String> quantifiedVariables,
- {bool debug: false}) {
- return new TestCase.fail(type1, type2, quantifiedVariables);
-}
-
-int numFailures = 0;
-
-void reportFailure(TestCase testCase, String message) {
- ++numFailures;
- fail('$message in `$testCase`');
-}
-
-main() {
- for (TestCase testCase in testCases) {
- test('$testCase', () {
- var env = new LazyTypeEnvironment();
- var type1 = env.parse(testCase.type1);
- var type2 = env.parse(testCase.type2);
- var quantifiedVariables =
- testCase.quantifiedVariables.map(env.getTypeParameter).toSet();
- var substitution = unifyTypes(type1, type2, quantifiedVariables);
- if (testCase.shouldSucceed) {
- if (substitution == null) {
- reportFailure(testCase, 'Unification failed');
- } else {
- for (var key in testCase.expectedSubstitution.keys) {
- var typeParameter = env.getTypeParameter(key);
- if (testCase.expectedSubstitution[key] == null) {
- if (substitution.containsKey(key)) {
- var actualType = substitution[typeParameter];
- reportFailure(
- testCase,
- 'Incorrect substitution '
- '`$key = $actualType` should be unbound');
- }
- } else {
- var expectedType = env.parse(testCase.expectedSubstitution[key]);
- var actualType = substitution[typeParameter];
- if (actualType != expectedType) {
- reportFailure(
- testCase,
- 'Incorrect substitution '
- '`$key = $actualType` should be `$key = $expectedType`');
- }
- }
- }
- var boundTypeVariables = testCase.expectedSubstitution.keys
- .where((name) => testCase.expectedSubstitution[name] != null);
- if (substitution.length != boundTypeVariables.length) {
- reportFailure(
- testCase,
- 'Substituted `${substitution.keys.join(',')}` '
- 'but should only substitute `${boundTypeVariables.join(',')}`');
- }
- }
- } else {
- if (substitution != null) {
- reportFailure(testCase, 'Unification was supposed to fail');
- }
- }
- });
- }
- if (numFailures > 0) {
- exit(1);
- }
-}
diff --git a/pkg/meta/analysis_options.yaml b/pkg/meta/analysis_options.yaml
deleted file mode 100644
index 4163582..0000000
--- a/pkg/meta/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- enable-experiment:
- - non-nullable
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 3428443..8833c58 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -6,6 +6,7 @@
import 'dart:io' hide File;
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/error.dart';
@@ -50,9 +51,10 @@
final Map<String, LineInfo> lineInfo;
final Context pathContext;
final String rootDirectory;
+ final bool allSourcesAlreadyMigrated;
- AnalysisResult(
- this.errors, this.lineInfo, this.pathContext, this.rootDirectory) {
+ AnalysisResult(this.errors, this.lineInfo, this.pathContext,
+ this.rootDirectory, this.allSourcesAlreadyMigrated) {
errors.sort((AnalysisError one, AnalysisError two) {
if (one.source != two.source) {
return one.source.fullName.compareTo(two.source.fullName);
@@ -635,7 +637,9 @@
logger.stdout(ansi.emphasized('Analyzing project...'));
_fixCodeProcessor = _FixCodeProcessor(context, this);
_dartFixListener = DartFixListener(
- DriverProviderImpl(resourceProvider, context), _exceptionReported);
+ DriverProviderImpl(resourceProvider, context),
+ _exceptionReported,
+ _fatalErrorReported);
nonNullableFix = createNonNullableFix(_dartFixListener, resourceProvider,
_fixCodeProcessor.getLineInfo, computeBindAddress(),
included: [options.directory],
@@ -803,6 +807,11 @@
}
}
+ void _fatalErrorReported(String detail) {
+ logger.stderr(detail);
+ throw MigrationExit(1);
+ }
+
void _exceptionReported(String detail) {
if (_hasExceptions) return;
_hasExceptions = true;
@@ -869,6 +878,14 @@
.stdout('Unresolved URIs found. Did you forget to run "pub get"?');
logger.stdout('');
}
+ if (analysisResult.allSourcesAlreadyMigrated) {
+ logger.stdout('''
+All files appear to have null safety already enabled. Did you update the
+language version prior to running "dart migrate"? If so, you need to un-do this
+(and re-run "pub get") prior to performing the migration.
+''');
+ logger.stdout('');
+ }
logger.stdout(
'Please fix the analysis issues (or, force generation of migration '
'suggestions by re-running with '
@@ -1030,7 +1047,11 @@
_progressBar = ProgressBar(_migrationCli.logger, pathsToProcess.length);
// Process each source file.
+ bool allSourcesAlreadyMigrated = true;
await processResources((ResolvedUnitResult result) async {
+ if (!result.unit.featureSet.isEnabled(Feature.non_nullable)) {
+ allSourcesAlreadyMigrated = false;
+ }
_progressBar.tick();
List<AnalysisError> errors = result.errors
.where((error) => error.severity == Severity.error)
@@ -1054,8 +1075,12 @@
}
}
- return AnalysisResult(analysisErrors, _migrationCli.lineInfo,
- _migrationCli.pathContext, _migrationCli.options.directory);
+ return AnalysisResult(
+ analysisErrors,
+ _migrationCli.lineInfo,
+ _migrationCli.pathContext,
+ _migrationCli.options.directory,
+ allSourcesAlreadyMigrated);
}
Future<MigrationState> runLaterPhases() async {
diff --git a/pkg/nnbd_migration/lib/src/front_end/dartfix_listener.dart b/pkg/nnbd_migration/lib/src/front_end/dartfix_listener.dart
index 378b136..1a4e769 100644
--- a/pkg/nnbd_migration/lib/src/front_end/dartfix_listener.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/dartfix_listener.dart
@@ -19,7 +19,10 @@
/// client.
final void Function(String detail) reportException;
- DartFixListener(this.server, this.reportException);
+ /// Callback that reports a fatal error to the client.
+ final void Function(String detail) reportFatalError;
+
+ DartFixListener(this.server, this.reportException, this.reportFatalError);
/// Record an edit to be sent to the client.
///
@@ -29,11 +32,6 @@
sourceChange.addEdit(source.fullName, -1, edit);
}
- /// Record a recommendation to be sent to the client.
- void addRecommendation(String description, [Location location]) {
- throw UnimplementedError('TODO(paulberry)');
- }
-
/// Record a source change to be sent to the client.
void addSourceFileEdit(
String description, Location location, SourceFileEdit fileEdit) {
diff --git a/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart b/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
index 8a5d668..a691876 100644
--- a/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
@@ -69,11 +69,6 @@
NullabilityMigration migration;
- /// If this flag has a value of `false`, then something happened to prevent
- /// at least one package from being marked as non-nullable.
- /// If this occurs, then don't update any code.
- bool _packageIsNNBD = true;
-
Future<MigrationState> Function() rerunFunction;
/// A list of the URLs corresponding to the included roots.
@@ -106,9 +101,6 @@
InstrumentationListener(migrationSummary: migrationSummary);
Future<void> finalizeUnit(ResolvedUnitResult result) async {
- if (!_packageIsNNBD) {
- return;
- }
migration.finalizeInput(result);
}
@@ -121,9 +113,6 @@
}
Future<void> prepareUnit(ResolvedUnitResult result) async {
- if (!_packageIsNNBD) {
- return;
- }
migration.prepareInput(result);
}
@@ -132,10 +121,6 @@
/// This means updating the pubspec.yaml file, the package_config.json
/// file, and the analysis_options.yaml file, each only if necessary.
void processPackage(Folder pkgFolder) {
- if (!_packageIsNNBD) {
- return;
- }
-
var pubspecFile = pkgFolder.getChildAssumingFile('pubspec.yaml');
if (!pubspecFile.exists) {
// If the pubspec file cannot be found, we do not attempt to change the
@@ -161,9 +146,6 @@
}
Future<void> processUnit(ResolvedUnitResult result) async {
- if (!_packageIsNNBD) {
- return;
- }
migration.processInput(result);
}
@@ -217,10 +199,6 @@
/// Updates the Package Config file to specify a minimum Dart SDK version
/// which supports null safety.
void _processConfigFile(Folder pkgFolder, _YamlFile pubspec) {
- if (!_packageIsNNBD) {
- return;
- }
-
var packageName = pubspec._getName();
if (packageName == null) {
return;
@@ -352,7 +330,7 @@
}
void _processPubspecException(String action, String pubspecPath, error) {
- listener.addRecommendation('''Failed to $action pubspec file
+ listener.reportFatalError('''Failed to $action pubspec file
$pubspecPath
$error
@@ -362,7 +340,7 @@
environment:
sdk: '$_intendedSdkVersionConstraint';
''');
- _packageIsNNBD = false;
+ throw StateError('listener.reportFatalError should never return');
}
/// Allows unit tests to shut down any rogue servers that have been started,
diff --git a/pkg/nnbd_migration/pubspec.yaml b/pkg/nnbd_migration/pubspec.yaml
index 5f57739..59072b4 100644
--- a/pkg/nnbd_migration/pubspec.yaml
+++ b/pkg/nnbd_migration/pubspec.yaml
@@ -21,6 +21,8 @@
yaml: ^2.1.15
dev_dependencies:
+ analysis_tool:
+ path: ../analysis_tool
http: '>=0.11.3+17 <0.13.0'
pedantic: ^1.9.0
test: ^1.6.4
diff --git a/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart b/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
index 6f87f89..0ca5ea4 100644
--- a/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
+++ b/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
@@ -201,7 +201,8 @@
// Compute the analysis results.
var server = DriverProviderImpl(resourceProvider, driver.analysisContext);
// Run the migration engine.
- var listener = DartFixListener(server, _exceptionReported);
+ var listener =
+ DartFixListener(server, _exceptionReported, _exceptionReported);
var instrumentationListener = InstrumentationListener();
var adapter = NullabilityMigrationAdapter(listener);
var migration = NullabilityMigration(adapter, getLineInfo,
diff --git a/pkg/nnbd_migration/test/front_end/test_all.dart b/pkg/nnbd_migration/test/front_end/test_all.dart
index 9a81148..7c88db8 100644
--- a/pkg/nnbd_migration/test/front_end/test_all.dart
+++ b/pkg/nnbd_migration/test/front_end/test_all.dart
@@ -7,6 +7,7 @@
import 'info_builder_test.dart' as info_builder;
import 'instrumentation_renderer_test.dart' as instrumentation_renderer;
import 'migration_info_test.dart' as migration_info;
+import 'migration_summary_test.dart' as migration_summary;
import 'navigation_tree_renderer_test.dart' as navigation_tree_renderer;
import 'offset_mapper_test.dart' as offset_mapper;
import 'region_renderer_test.dart' as region_renderer;
@@ -17,6 +18,7 @@
info_builder.main();
instrumentation_renderer.main();
migration_info.main();
+ migration_summary.main();
navigation_tree_renderer.main();
offset_mapper.main();
region_renderer.main();
diff --git a/pkg/nnbd_migration/test/migration_cli_test.dart b/pkg/nnbd_migration/test/migration_cli_test.dart
index ce0ec97..35957ce 100644
--- a/pkg/nnbd_migration/test/migration_cli_test.dart
+++ b/pkg/nnbd_migration/test/migration_cli_test.dart
@@ -144,7 +144,8 @@
@override
Set<String> computePathsToProcess(DriverBasedAnalysisContext context) =>
- cli._test.overridePathsToProcess ?? super.computePathsToProcess(context);
+ cli._test.overridePathsToProcess ??
+ _sortPaths(super.computePathsToProcess(context));
@override
NonNullableFix createNonNullableFix(
@@ -185,6 +186,13 @@
bool shouldBeMigrated(DriverBasedAnalysisContext context, String path) =>
cli._test.overrideShouldBeMigrated?.call(path) ??
super.shouldBeMigrated(context, path);
+
+ /// Sorts the paths in [paths] for repeatability of migration tests.
+ Set<String> _sortPaths(Set<String> paths) {
+ var pathList = paths.toList();
+ pathList.sort();
+ return pathList.toSet();
+ }
}
abstract class _MigrationCliTestBase {
@@ -742,6 +750,10 @@
contains(
'analysis errors will result in erroneous migration suggestions'));
expect(output, contains('Please fix the analysis issues'));
+ expect(
+ output,
+ isNot(
+ contains('All files appear to have null safety already enabled')));
}
test_lifecycle_ignore_errors_enable() async {
@@ -806,6 +818,30 @@
expect(output, isNot(contains('package:bar/bar.dart')));
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/44118')
+ test_lifecycle_issue_44118() async {
+ var projectContents = simpleProject(sourceText: '''
+int f() => null
+''');
+ projectContents['lib/foo.dart'] = '''
+import 'test.dart';
+''';
+ var projectDir = createProjectDir(projectContents);
+ await assertRunFailure([projectDir]);
+ var output = logger.stdoutBuffer.toString();
+ expect(output, contains('1 analysis issue found'));
+ var sep = resourceProvider.pathContext.separator;
+ expect(
+ output,
+ contains("error • Expected to find ';' at lib${sep}test.dart:1:12 • "
+ '(expected_token)'));
+ expect(
+ output,
+ contains(
+ 'analysis errors will result in erroneous migration suggestions'));
+ expect(output, contains('Please fix the analysis issues'));
+ }
+
test_lifecycle_no_preview() async {
var projectContents = simpleProject();
var projectDir = createProjectDir(projectContents);
@@ -1459,6 +1495,10 @@
expect(output,
contains('Unresolved URIs found. Did you forget to run "pub get"?'));
expect(output, contains('Please fix the analysis issues'));
+ expect(
+ output,
+ isNot(
+ contains('All files appear to have null safety already enabled')));
}
test_migrate_path_absolute() {
@@ -1784,7 +1824,10 @@
var projectDir = createProjectDir(projectContents);
var cliRunner = _createCli()
.decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- expect(() async => await cliRunner.run(), throwsUnsupportedError);
+ var message = await assertErrorExit(
+ cliRunner, () async => await cliRunner.run(),
+ withUsage: false);
+ expect(message, contains('Failed to parse pubspec file'));
}
test_pubspec_with_sdk_version_beta() async {
@@ -1869,6 +1912,9 @@
errorOutput,
contains("A value of type 'Null' can't be returned from function 'f' "
"because it has a return type of 'int'"));
+ expect(errorOutput, contains('''
+All files appear to have null safety already enabled. Did you update the
+language version prior to running "dart migrate"?'''));
}
String _getHelpText({@required bool verbose}) {
diff --git a/pkg/nnbd_migration/test/preview/preview_site_test.dart b/pkg/nnbd_migration/test/preview/preview_site_test.dart
index f32b003..43fd177 100644
--- a/pkg/nnbd_migration/test/preview/preview_site_test.dart
+++ b/pkg/nnbd_migration/test/preview/preview_site_test.dart
@@ -36,7 +36,8 @@
}
void setUp() {
- dartfixListener = DartFixListener(null, _exceptionReported);
+ dartfixListener =
+ DartFixListener(null, _exceptionReported, _exceptionReported);
resourceProvider = MemoryResourceProvider();
final migrationInfo = MigrationInfo({}, {}, null, null);
state = MigrationState(null, null, dartfixListener, null);
@@ -190,7 +191,8 @@
@override
void setUp() {
super.setUp();
- dartfixListener = DartFixListener(null, _exceptionReported);
+ dartfixListener =
+ DartFixListener(null, _exceptionReported, _exceptionReported);
final migrationInfo = MigrationInfo({}, {}, null, null);
state = MigrationState(null, null, dartfixListener, null);
nodeMapper = state.nodeMapper;
diff --git a/pkg/nnbd_migration/test/test_all.dart b/pkg/nnbd_migration/test/test_all.dart
index b82bafb..c2f9b7f 100644
--- a/pkg/nnbd_migration/test/test_all.dart
+++ b/pkg/nnbd_migration/test/test_all.dart
@@ -26,6 +26,7 @@
import 'preview/test_all.dart' as preview;
import 'utilities/test_all.dart' as utilities;
import 'variables_test.dart' as variables;
+import 'verify_tests_test.dart' as verify_tests;
main() {
defineReflectiveSuite(() {
@@ -48,5 +49,6 @@
preview.main();
utilities.main();
variables.main();
+ verify_tests.main();
});
}
diff --git a/pkg/nnbd_migration/test/verify_tests_test.dart b/pkg/nnbd_migration/test/verify_tests_test.dart
new file mode 100644
index 0000000..af19088
--- /dev/null
+++ b/pkg/nnbd_migration/test/verify_tests_test.dart
@@ -0,0 +1,15 @@
+// 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:analysis_tool/package_root.dart' as package_root;
+import 'package:analysis_tool/verify_tests.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+
+void main() {
+ var provider = PhysicalResourceProvider.INSTANCE;
+ var packageRoot = provider.pathContext.normalize(package_root.packageRoot);
+ var pathToAnalyze = provider.pathContext.join(packageRoot, 'nnbd_migration');
+ var testDirPath = provider.pathContext.join(pathToAnalyze, 'test');
+ VerifyTests(testDirPath).build();
+}
diff --git a/pkg/nnbd_migration/tool/summary_stats.dart b/pkg/nnbd_migration/tool/summary_stats.dart
new file mode 100644
index 0000000..79afca0
--- /dev/null
+++ b/pkg/nnbd_migration/tool/summary_stats.dart
@@ -0,0 +1,54 @@
+import 'dart:convert' show jsonDecode;
+import 'dart:io';
+
+void main(List<String> args) {
+ var jsonPath = args[0];
+ var json =
+ jsonDecode(File(jsonPath).readAsStringSync()) as Map<String, Object>;
+ var changes = json['changes'] as Map<String, Object>;
+ var byPath = changes['byPath'] as Map<String, Object>;
+ if (args.isEmpty) {
+ print('''
+Usage: summary_stats.dart <summary_file> [category_name]
+
+Prints statistics of `dart migrate` suggestions summary, created with the
+`--summary` flag of `dart migrate`.
+
+If [category_name] is not given, this prints the total number of suggestions
+which the tool made, per category.
+
+If [category_name] is given, this prints the file names and suggestion counts of
+each file with one or more suggestions categorized as [category_name].
+''');
+ } else if (args.length == 1) {
+ _printTotals(byPath);
+ } else {
+ var category = args[1];
+ _printCategory(byPath, category);
+ }
+}
+
+/// Prints the file names and counts of files with suggestions of [category].
+void _printCategory(Map<String, Object> byPath, String category) {
+ byPath.forEach((String path, Object value) {
+ var counts = value as Map<String, Object>;
+ if (counts.containsKey(category)) {
+ print('$path: ${counts[category]}');
+ }
+ });
+}
+
+/// Prints the total number of suggestions for each category.
+void _printTotals(Map<String, Object> byPath) {
+ var summary = <String, int>{};
+ for (var file in byPath.values.cast<Map<Object, Object>>()) {
+ file.forEach((category, count) {
+ summary.putIfAbsent(category as String, () => 0);
+ summary[category as String] += count as int;
+ });
+ }
+ var categories = summary.keys.toList()..sort();
+ for (var category in categories) {
+ print('$category: ${summary[category]}');
+ }
+}
diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart
index 0b3fb76..be34361 100644
--- a/pkg/test_runner/lib/src/test_configurations.dart
+++ b/pkg/test_runner/lib/src/test_configurations.dart
@@ -41,7 +41,6 @@
Path('tests/dart2js_2'),
Path('tests/dartdevc'),
Path('tests/dartdevc_2'),
- Path('tests/kernel'),
Path('tests/language'),
Path('tests/language_2'),
Path('tests/lib'),
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 97cf03a..3df5836 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -50,7 +50,7 @@
bool get supportsSetLiterals => false;
@override
- bool get supportsLateFields => !flags.forceLateLoweringForTesting;
+ int get enabledLateLowerings => flags.forceLateLoweringsForTesting;
@override
bool get supportsLateLoweringSentinel =>
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 905cb26..1ff4a38 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -293,11 +293,8 @@
class SpawnIsolateTask : public ThreadPool::Task {
public:
SpawnIsolateTask(Isolate* parent_isolate,
- std::unique_ptr<IsolateSpawnState> state,
- bool in_new_isolate_group)
- : parent_isolate_(parent_isolate),
- state_(std::move(state)),
- in_new_isolate_group_(in_new_isolate_group) {
+ std::unique_ptr<IsolateSpawnState> state)
+ : parent_isolate_(parent_isolate), state_(std::move(state)) {
parent_isolate->IncrementSpawnCount();
}
@@ -308,68 +305,37 @@
}
void Run() override {
- auto group = state_->isolate_group();
+ const char* name = (state_->debug_name() == nullptr)
+ ? state_->function_name()
+ : state_->debug_name();
+ ASSERT(name != nullptr);
- // The create isolate group call back is mandatory. If not provided we
+ auto group = state_->isolate_group();
+ if (!FLAG_enable_isolate_groups || group == nullptr) {
+ RunHeavyweight(name);
+ } else {
+ RunLightweight(name);
+ }
+ }
+
+ void RunHeavyweight(const char* name) {
+ // The create isolate group callback is mandatory. If not provided we
// cannot spawn isolates.
- Dart_IsolateGroupCreateCallback create_group_callback =
- Isolate::CreateGroupCallback();
+ auto create_group_callback = Isolate::CreateGroupCallback();
if (create_group_callback == nullptr) {
FailedSpawn("Isolate spawn is not supported by this Dart embedder\n");
return;
}
- // The initialize callback is optional atm, we fall back to creating isolate
- // groups if it was not provided.
- Dart_InitializeIsolateCallback initialize_callback =
- Isolate::InitializeCallback();
-
- const char* name = (state_->debug_name() == NULL) ? state_->function_name()
- : state_->debug_name();
- ASSERT(name != NULL);
-
- // Create a new isolate.
char* error = nullptr;
- Isolate* isolate = nullptr;
- if (!FLAG_enable_isolate_groups || group == nullptr ||
- initialize_callback == nullptr || in_new_isolate_group_) {
- // Make a copy of the state's isolate flags and hand it to the callback.
- Dart_IsolateFlags api_flags = *(state_->isolate_flags());
- isolate = reinterpret_cast<Isolate*>((create_group_callback)(
- state_->script_url(), name, nullptr, state_->package_config(),
- &api_flags, parent_isolate_->init_callback_data(), &error));
- parent_isolate_->DecrementSpawnCount();
- parent_isolate_ = nullptr;
- } else {
- if (initialize_callback == nullptr) {
- FailedSpawn("Isolate spawn is not supported by this embedder.");
- return;
- }
-#if defined(DART_PRECOMPILED_RUNTIME)
- isolate = CreateWithinExistingIsolateGroupAOT(group, name, &error);
-#else
- isolate = CreateWithinExistingIsolateGroup(group, name, &error);
-#endif
- parent_isolate_->DecrementSpawnCount();
- parent_isolate_ = nullptr;
- if (isolate == nullptr) {
- FailedSpawn(error);
- free(error);
- return;
- }
-
- void* child_isolate_data = nullptr;
- bool success = initialize_callback(&child_isolate_data, &error);
- isolate->set_init_callback_data(child_isolate_data);
- if (!success) {
- Dart_ShutdownIsolate();
- FailedSpawn(error);
- free(error);
- return;
- }
- Dart_ExitIsolate();
- }
+ // Make a copy of the state's isolate flags and hand it to the callback.
+ Dart_IsolateFlags api_flags = *(state_->isolate_flags());
+ Isolate* isolate = reinterpret_cast<Isolate*>((create_group_callback)(
+ state_->script_url(), name, nullptr, state_->package_config(),
+ &api_flags, parent_isolate_->init_callback_data(), &error));
+ parent_isolate_->DecrementSpawnCount();
+ parent_isolate_ = nullptr;
if (isolate == nullptr) {
FailedSpawn(error);
@@ -377,20 +343,66 @@
return;
}
- if (state_->origin_id() != ILLEGAL_PORT) {
- // For isolates spawned using spawnFunction we set the origin_id
- // to the origin_id of the parent isolate.
- isolate->set_origin_id(state_->origin_id());
+ Run(isolate);
+ }
+
+ void RunLightweight(const char* name) {
+ // The create isolate initialize callback is mandatory if
+ // --enable-isolate-groups was passed.
+ auto initialize_callback = Isolate::InitializeCallback();
+ if (initialize_callback == nullptr) {
+ FailedSpawn(
+ "Lightweight isolate spawn is not supported by this Dart embedder\n");
+ return;
}
- MutexLocker ml(isolate->mutex());
- state_->set_isolate(isolate);
- isolate->set_spawn_state(std::move(state_));
- if (isolate->is_runnable()) {
- isolate->Run();
+
+ char* error = nullptr;
+
+ auto group = state_->isolate_group();
+#if defined(DART_PRECOMPILED_RUNTIME)
+ Isolate* isolate = CreateWithinExistingIsolateGroupAOT(group, name, &error);
+#else
+ Isolate* isolate = CreateWithinExistingIsolateGroup(group, name, &error);
+#endif
+ parent_isolate_->DecrementSpawnCount();
+ parent_isolate_ = nullptr;
+
+ if (isolate == nullptr) {
+ FailedSpawn(error);
+ free(error);
+ return;
}
+
+ void* child_isolate_data = nullptr;
+ const bool success = initialize_callback(&child_isolate_data, &error);
+ if (!success) {
+ Dart_ShutdownIsolate();
+ FailedSpawn(error);
+ free(error);
+ return;
+ }
+
+ isolate->set_init_callback_data(child_isolate_data);
+ Dart_ExitIsolate();
+ Run(isolate);
}
private:
+ void Run(Isolate* child) {
+ state_->set_isolate(child);
+
+ MutexLocker ml(child->mutex());
+ child->set_origin_id(state_->origin_id());
+ child->set_spawn_state(std::move(state_));
+
+ // If the isolate is not marked as runnable, then the embedder might do so
+ // later on and the launch of the isolate will happen inside
+ // `Dart_IsolateMakeRunnable`.
+ if (child->is_runnable()) {
+ child->Run();
+ }
+ }
+
void FailedSpawn(const char* error) {
ReportError(error != nullptr
? error
@@ -410,7 +422,6 @@
Isolate* parent_isolate_;
std::unique_ptr<IsolateSpawnState> state_;
- bool in_new_isolate_group_;
DISALLOW_COPY_AND_ASSIGN(SpawnIsolateTask);
};
@@ -466,18 +477,19 @@
packageConfig.IsNull() ? NULL : String2UTF8(packageConfig);
const char* utf8_debug_name =
debugName.IsNull() ? NULL : String2UTF8(debugName);
+ const bool in_new_isolate_group = newIsolateGroup.value();
std::unique_ptr<IsolateSpawnState> state(new IsolateSpawnState(
port.Id(), isolate->origin_id(), String2UTF8(script_uri), func,
&message_buffer, utf8_package_config, paused.value(), fatal_errors,
- on_exit_port, on_error_port, utf8_debug_name, isolate->group()));
+ on_exit_port, on_error_port, utf8_debug_name,
+ in_new_isolate_group ? nullptr : isolate->group()));
// Since this is a call to Isolate.spawn, copy the parent isolate's code.
state->isolate_flags()->copy_parent_code = true;
- const bool in_new_isolate_group = newIsolateGroup.value();
- isolate->group()->thread_pool()->Run<SpawnIsolateTask>(
- isolate, std::move(state), in_new_isolate_group);
+ isolate->group()->thread_pool()->Run<SpawnIsolateTask>(isolate,
+ std::move(state));
return Object::null();
}
}
@@ -581,9 +593,8 @@
// Since this is a call to Isolate.spawnUri, don't copy the parent's code.
state->isolate_flags()->copy_parent_code = false;
- const bool in_new_isolate_group = false;
- isolate->group()->thread_pool()->Run<SpawnIsolateTask>(
- isolate, std::move(state), in_new_isolate_group);
+ isolate->group()->thread_pool()->Run<SpawnIsolateTask>(isolate,
+ std::move(state));
return Object::null();
}
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 1e9d2ff..71c5428f 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -768,6 +768,7 @@
ldr(LR, target);
blx(LR);
}
+ void Call(const Code& code) { BranchLink(code); }
void CallCFunction(Address target) { Call(target); }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index b74553e..377cc4e 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1461,6 +1461,7 @@
ldr(LR, target);
blr(LR);
}
+ void Call(const Code& code) { BranchLink(code); }
void CallCFunction(Address target) { Call(target); }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index e943f75..535b34c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2304,6 +2304,38 @@
}
#if !defined(TARGET_ARCH_IA32)
+// Expected inputs (from TypeTestABI):
+// - kInstanceReg: instance (preserved).
+// - kInstantiatorTypeArgumentsReg: instantiator type arguments
+// (for test_kind == kTestTypeFourArg or test_kind == kTestTypeSixArg).
+// - kFunctionTypeArgumentsReg: function type arguments
+// (for test_kind == kTestTypeFourArg or test_kind == kTestTypeSixArg).
+//
+// See the arch-specific GenerateSubtypeNTestCacheStub method to see which
+// registers may need saving across this call.
+SubtypeTestCachePtr FlowGraphCompiler::GenerateCallSubtypeTestStub(
+ TypeTestStubKind test_kind,
+ compiler::Label* is_instance_lbl,
+ compiler::Label* is_not_instance_lbl) {
+ const SubtypeTestCache& type_test_cache =
+ SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
+ __ LoadUniqueObject(TypeTestABI::kSubtypeTestCacheReg, type_test_cache);
+ if (test_kind == kTestTypeOneArg) {
+ __ Call(StubCode::Subtype1TestCache());
+ } else if (test_kind == kTestTypeTwoArgs) {
+ __ Call(StubCode::Subtype2TestCache());
+ } else if (test_kind == kTestTypeFourArgs) {
+ __ Call(StubCode::Subtype4TestCache());
+ } else if (test_kind == kTestTypeSixArgs) {
+ __ Call(StubCode::Subtype6TestCache());
+ } else {
+ UNREACHABLE();
+ }
+ GenerateBoolToJump(TypeTestABI::kSubtypeTestCacheResultReg, is_instance_lbl,
+ is_not_instance_lbl);
+ return type_test_cache.raw();
+}
+
// Generates an assignable check for a given object. Emits no code if the
// destination type is known at compile time and is a top type. See
// GenerateCallerChecksForAssertAssignable for other optimized cases.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 1965d97..31d849d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -1085,12 +1085,10 @@
TypeTestStubKind GetTypeTestStubKindForTypeParameter(
const TypeParameter& type_param);
+ // Takes input from TypeTestABI registers (or stack on IA32), see
+ // StubCodeCompiler::GenerateSubtypeNTestCacheStub for caller-save registers.
SubtypeTestCachePtr GenerateCallSubtypeTestStub(
TypeTestStubKind test_kind,
- Register instance_reg,
- Register instantiator_type_arguments_reg,
- Register function_type_arguments_reg,
- Register temp_reg,
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 66f966d..5f07a68 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -224,51 +224,6 @@
__ Bind(&fall_through);
}
-// R0: instance (must be preserved).
-// R2: instantiator type arguments (if used).
-// R1: function type arguments (if used).
-// R3: type test cache.
-SubtypeTestCachePtr FlowGraphCompiler::GenerateCallSubtypeTestStub(
- TypeTestStubKind test_kind,
- Register instance_reg,
- Register instantiator_type_arguments_reg,
- Register function_type_arguments_reg,
- Register temp_reg,
- compiler::Label* is_instance_lbl,
- compiler::Label* is_not_instance_lbl) {
- ASSERT(instance_reg == R0);
- ASSERT(temp_reg == kNoRegister); // Unused on ARM.
- const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
- __ LoadUniqueObject(R3, type_test_cache);
- if (test_kind == kTestTypeOneArg) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(StubCode::Subtype1TestCache());
- } else if (test_kind == kTestTypeTwoArgs) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(StubCode::Subtype2TestCache());
- } else if (test_kind == kTestTypeFourArgs) {
- ASSERT(instantiator_type_arguments_reg ==
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- ASSERT(function_type_arguments_reg ==
- TypeTestABI::kFunctionTypeArgumentsReg);
- __ BranchLink(StubCode::Subtype4TestCache());
- } else if (test_kind == kTestTypeSixArgs) {
- ASSERT(instantiator_type_arguments_reg ==
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- ASSERT(function_type_arguments_reg ==
- TypeTestABI::kFunctionTypeArgumentsReg);
- __ BranchLink(StubCode::Subtype6TestCache());
- } else {
- UNREACHABLE();
- }
- // Result is in R1: null -> not found, otherwise Bool::True or Bool::False.
- GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl);
- return type_test_cache.raw();
-}
-
// Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
// type test is conclusive, otherwise fallthrough if a type test could not
// be completed.
@@ -326,14 +281,8 @@
}
// Regular subtype test cache involving instance's type arguments.
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = kNoRegister;
- // R0: instance (must be preserved).
- return GenerateCallSubtypeTestStub(
- kTestTypeTwoArgs, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
@@ -444,24 +393,18 @@
__ b(is_instance_lbl, EQ);
}
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = kNoRegister;
- return GenerateCallSubtypeTestStub(kTestTypeOneArg, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeOneArg, is_instance_lbl,
+ is_not_instance_lbl);
}
// Generates inlined check if 'type' is a type parameter or type itself
-// R0: instance (preserved).
+// TypeTestABI::kInstanceReg: instance (preserved).
SubtypeTestCachePtr FlowGraphCompiler::GenerateUninstantiatedTypeTest(
TokenPosition token_pos,
const AbstractType& type,
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl) {
__ Comment("UninstantiatedTypeTest");
- const Register kTempReg = kNoRegister;
ASSERT(!type.IsInstantiated());
ASSERT(!type.IsFunctionType());
// Skip check if destination is a dynamic type.
@@ -480,40 +423,40 @@
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
__ CompareObject(kTypeArgumentsReg, Object::null_object());
__ b(is_instance_lbl, EQ);
- __ ldr(R3, compiler::FieldAddress(
- kTypeArgumentsReg,
- compiler::target::TypeArguments::type_at_offset(
- type_param.index())));
+ __ ldr(
+ TypeTestABI::kScratchReg,
+ compiler::FieldAddress(kTypeArgumentsReg,
+ compiler::target::TypeArguments::type_at_offset(
+ type_param.index())));
// R3: concrete type of type.
// Check if type argument is dynamic, Object?, or void.
- __ CompareObject(R3, Object::dynamic_type());
+ __ CompareObject(TypeTestABI::kScratchReg, Object::dynamic_type());
__ b(is_instance_lbl, EQ);
__ CompareObject(
- R3, Type::ZoneHandle(
- zone(), isolate()->object_store()->nullable_object_type()));
+ TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(),
+ isolate()->object_store()->nullable_object_type()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R3, Object::void_type());
+ __ CompareObject(TypeTestABI::kScratchReg, Object::void_type());
__ b(is_instance_lbl, EQ);
// For Smi check quickly against int and num interfaces.
compiler::Label not_smi;
- __ tst(R0, compiler::Operand(kSmiTagMask)); // Value is Smi?
+ __ tst(TypeTestABI::kInstanceReg,
+ compiler::Operand(kSmiTagMask)); // Value is Smi?
__ b(¬_smi, NE);
- __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType()));
+ __ CompareObject(TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(), Type::IntType()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number()));
+ __ CompareObject(TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(), Type::Number()));
__ b(is_instance_lbl, EQ);
// Smi can be handled by type test cache.
__ Bind(¬_smi);
const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
- const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
- zone(), GenerateCallSubtypeTestStub(
- test_kind, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl));
- return type_test_cache.raw();
+ return GenerateCallSubtypeTestStub(test_kind, is_instance_lbl,
+ is_not_instance_lbl);
}
if (type.IsType()) {
// Smi is FutureOr<T>, when T is a top type or int or num.
@@ -528,11 +471,8 @@
(1 << TypeTestABI::kInstantiatorTypeArgumentsReg));
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- return GenerateCallSubtypeTestStub(
- kTestTypeFourArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeFourArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -554,12 +494,8 @@
(1 << TypeTestABI::kInstantiatorTypeArgumentsReg));
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- const Register kTempReg = kNoRegister;
- return GenerateCallSubtypeTestStub(
- kTestTypeSixArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeSixArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
// Inputs:
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 14cb38c..803667f 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -214,50 +214,6 @@
__ Bind(&fall_through);
}
-// R0: instance (must be preserved).
-// R2: instantiator type arguments (if used).
-// R1: function type arguments (if used).
-SubtypeTestCachePtr FlowGraphCompiler::GenerateCallSubtypeTestStub(
- TypeTestStubKind test_kind,
- Register instance_reg,
- Register instantiator_type_arguments_reg,
- Register function_type_arguments_reg,
- Register temp_reg,
- compiler::Label* is_instance_lbl,
- compiler::Label* is_not_instance_lbl) {
- ASSERT(instance_reg == R0);
- ASSERT(temp_reg == kNoRegister); // Unused on ARM64.
- const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
- __ LoadUniqueObject(R3, type_test_cache);
- if (test_kind == kTestTypeOneArg) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(StubCode::Subtype1TestCache());
- } else if (test_kind == kTestTypeTwoArgs) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(StubCode::Subtype2TestCache());
- } else if (test_kind == kTestTypeFourArgs) {
- ASSERT(instantiator_type_arguments_reg ==
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- ASSERT(function_type_arguments_reg ==
- TypeTestABI::kFunctionTypeArgumentsReg);
- __ BranchLink(StubCode::Subtype4TestCache());
- } else if (test_kind == kTestTypeSixArgs) {
- ASSERT(instantiator_type_arguments_reg ==
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- ASSERT(function_type_arguments_reg ==
- TypeTestABI::kFunctionTypeArgumentsReg);
- __ BranchLink(StubCode::Subtype6TestCache());
- } else {
- UNREACHABLE();
- }
- // Result is in R1: null -> not found, otherwise Bool::True or Bool::False.
- GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl);
- return type_test_cache.raw();
-}
-
// Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
// type test is conclusive, otherwise fallthrough if a type test could not
// be completed.
@@ -311,14 +267,8 @@
}
}
// Regular subtype test cache involving instance's type arguments.
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = kNoRegister;
- // R0: instance (must be preserved).
- return GenerateCallSubtypeTestStub(
- kTestTypeTwoArgs, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
@@ -426,24 +376,18 @@
__ b(is_instance_lbl, EQ);
}
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = kNoRegister;
- return GenerateCallSubtypeTestStub(kTestTypeOneArg, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeOneArg, is_instance_lbl,
+ is_not_instance_lbl);
}
// Generates inlined check if 'type' is a type parameter or type itself
-// R0: instance (preserved).
+// TypeTestABI::kInstanceReg: instance (preserved).
SubtypeTestCachePtr FlowGraphCompiler::GenerateUninstantiatedTypeTest(
TokenPosition token_pos,
const AbstractType& type,
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl) {
__ Comment("UninstantiatedTypeTest");
- const Register kTempReg = kNoRegister;
ASSERT(!type.IsInstantiated());
ASSERT(!type.IsFunctionType());
// Skip check if destination is a dynamic type.
@@ -461,37 +405,35 @@
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
__ CompareObject(kTypeArgumentsReg, Object::null_object());
__ b(is_instance_lbl, EQ);
- __ LoadFieldFromOffset(R3, kTypeArgumentsReg,
+ __ LoadFieldFromOffset(TypeTestABI::kScratchReg, kTypeArgumentsReg,
TypeArguments::type_at_offset(type_param.index()));
// R3: concrete type of type.
// Check if type argument is dynamic, Object?, or void.
- __ CompareObject(R3, Object::dynamic_type());
+ __ CompareObject(TypeTestABI::kScratchReg, Object::dynamic_type());
__ b(is_instance_lbl, EQ);
__ CompareObject(
- R3, Type::ZoneHandle(
- zone(), isolate()->object_store()->nullable_object_type()));
+ TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(),
+ isolate()->object_store()->nullable_object_type()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R3, Object::void_type());
+ __ CompareObject(TypeTestABI::kScratchReg, Object::void_type());
__ b(is_instance_lbl, EQ);
// For Smi check quickly against int and num interfaces.
compiler::Label not_smi;
- __ BranchIfNotSmi(R0, ¬_smi);
- __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType()));
+ __ BranchIfNotSmi(TypeTestABI::kInstanceReg, ¬_smi);
+ __ CompareObject(TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(), Type::IntType()));
__ b(is_instance_lbl, EQ);
- __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number()));
+ __ CompareObject(TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(), Type::Number()));
__ b(is_instance_lbl, EQ);
// Smi can be handled by type test cache.
__ Bind(¬_smi);
const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
- const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
- zone(), GenerateCallSubtypeTestStub(
- test_kind, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl));
- return type_test_cache.raw();
+ return GenerateCallSubtypeTestStub(test_kind, is_instance_lbl,
+ is_not_instance_lbl);
}
if (type.IsType()) {
// Smi is FutureOr<T>, when T is a top type or int or num.
@@ -503,11 +445,8 @@
compiler::Address(SP, 0 * kWordSize, compiler::Address::PairOffset));
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator.
- return GenerateCallSubtypeTestStub(
- kTestTypeFourArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeFourArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -526,12 +465,8 @@
compiler::Address(SP, 0 * kWordSize, compiler::Address::PairOffset));
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- const Register kTempReg = kNoRegister;
- return GenerateCallSubtypeTestStub(
- kTestTypeSixArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeSixArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
// Inputs:
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 83f47d6..3525a02 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -195,52 +195,48 @@
__ Bind(&fall_through);
}
-// Clobbers ECX.
+// Input registers (from TypeTestABI):
+// - kInstanceReg: instance.
+// - kInstantiatorTypeArgumentsReg: instantiator type arguments
+// (for test_kind == kTestTypeFourArg or test_kind == kTestTypeSixArg).
+// - kFunctionTypeArgumentsReg: function type arguments
+// (for test_kind == kTestTypeFourArg or test_kind == kTestTypeSixArg).
+//
+// Only preserves kInstanceReg from TypeTestABI, all other TypeTestABI
+// registers may be used and thus must be saved by the caller.
SubtypeTestCachePtr FlowGraphCompiler::GenerateCallSubtypeTestStub(
TypeTestStubKind test_kind,
- Register instance_reg,
- Register instantiator_type_arguments_reg,
- Register function_type_arguments_reg,
- Register temp_reg,
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl) {
const SubtypeTestCache& type_test_cache =
SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
- const compiler::Immediate& raw_null =
- compiler::Immediate(static_cast<intptr_t>(Object::null()));
- __ LoadObject(temp_reg, type_test_cache);
- __ pushl(temp_reg); // Subtype test cache.
- __ pushl(instance_reg); // Instance.
+ __ LoadObject(TypeTestABI::kSubtypeTestCacheReg, type_test_cache);
+ __ pushl(TypeTestABI::kSubtypeTestCacheReg);
+ __ pushl(TypeTestABI::kInstanceReg);
if (test_kind == kTestTypeOneArg) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ pushl(raw_null);
- __ pushl(raw_null);
+ __ PushObject(Object::null_object());
+ __ PushObject(Object::null_object());
__ Call(StubCode::Subtype1TestCache());
} else if (test_kind == kTestTypeTwoArgs) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ pushl(raw_null);
- __ pushl(raw_null);
+ __ PushObject(Object::null_object());
+ __ PushObject(Object::null_object());
__ Call(StubCode::Subtype2TestCache());
} else if (test_kind == kTestTypeFourArgs) {
- __ pushl(instantiator_type_arguments_reg);
- __ pushl(function_type_arguments_reg);
+ __ pushl(TypeTestABI::kInstantiatorTypeArgumentsReg);
+ __ pushl(TypeTestABI::kFunctionTypeArgumentsReg);
__ Call(StubCode::Subtype4TestCache());
} else if (test_kind == kTestTypeSixArgs) {
- __ pushl(instantiator_type_arguments_reg);
- __ pushl(function_type_arguments_reg);
+ __ pushl(TypeTestABI::kInstantiatorTypeArgumentsReg);
+ __ pushl(TypeTestABI::kFunctionTypeArgumentsReg);
__ Call(StubCode::Subtype6TestCache());
} else {
UNREACHABLE();
}
- // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False.
- ASSERT(instance_reg != ECX);
- ASSERT(temp_reg != ECX);
__ Drop(2);
- __ popl(instance_reg); // Restore receiver.
- __ popl(temp_reg); // Discard.
- GenerateBoolToJump(ECX, is_instance_lbl, is_not_instance_lbl);
+ __ popl(TypeTestABI::kInstanceReg); // Restore receiver.
+ __ Drop(1);
+ GenerateBoolToJump(TypeTestABI::kSubtypeTestCacheResultReg, is_instance_lbl,
+ is_not_instance_lbl);
return type_test_cache.raw();
}
@@ -300,13 +296,8 @@
}
}
// Regular subtype test cache involving instance's type arguments.
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = EDI;
- return GenerateCallSubtypeTestStub(
- kTestTypeTwoArgs, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
@@ -415,13 +406,8 @@
__ j(EQUAL, is_instance_lbl);
}
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = EDI;
- return GenerateCallSubtypeTestStub(kTestTypeOneArg, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeOneArg, is_instance_lbl,
+ is_not_instance_lbl);
}
// Generates inlined check if 'type' is a type parameter or type itself
@@ -433,18 +419,19 @@
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl) {
__ Comment("UninstantiatedTypeTest");
- const Register kTempReg = EDI;
ASSERT(!type.IsInstantiated());
ASSERT(!type.IsFunctionType());
// Skip check if destination is a dynamic type.
const compiler::Immediate& raw_null =
compiler::Immediate(static_cast<intptr_t>(Object::null()));
if (type.IsTypeParameter()) {
+ const Register kTempReg = EDI;
const TypeParameter& type_param = TypeParameter::Cast(type);
- __ movl(EDX, compiler::Address(
- ESP, 1 * kWordSize)); // Get instantiator type args.
- __ movl(ECX,
+ __ movl(
+ TypeTestABI::kInstantiatorTypeArgumentsReg,
+ compiler::Address(ESP, 1 * kWordSize)); // Get instantiator type args.
+ __ movl(TypeTestABI::kFunctionTypeArgumentsReg,
compiler::Address(ESP, 0 * kWordSize)); // Get function type args.
// EDX: instantiator type arguments.
// ECX: function type arguments.
@@ -455,39 +442,36 @@
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
__ cmpl(kTypeArgumentsReg, raw_null);
__ j(EQUAL, is_instance_lbl);
- __ movl(EDI, compiler::FieldAddress(
- kTypeArgumentsReg,
- TypeArguments::type_at_offset(type_param.index())));
+ __ movl(kTempReg, compiler::FieldAddress(
+ kTypeArgumentsReg,
+ TypeArguments::type_at_offset(type_param.index())));
// EDI: concrete type of type.
// Check if type argument is dynamic, Object?, or void.
- __ CompareObject(EDI, Object::dynamic_type());
+ __ CompareObject(kTempReg, Object::dynamic_type());
__ j(EQUAL, is_instance_lbl);
__ CompareObject(
- EDI, Type::ZoneHandle(
- zone(), isolate()->object_store()->nullable_object_type()));
+ kTempReg,
+ Type::ZoneHandle(zone(),
+ isolate()->object_store()->nullable_object_type()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(EDI, Object::void_type());
+ __ CompareObject(kTempReg, Object::void_type());
__ j(EQUAL, is_instance_lbl);
// For Smi check quickly against int and num interfaces.
compiler::Label not_smi;
- __ testl(EAX, compiler::Immediate(kSmiTagMask)); // Value is Smi?
+ __ testl(TypeTestABI::kInstanceReg,
+ compiler::Immediate(kSmiTagMask)); // Value is Smi?
__ j(NOT_ZERO, ¬_smi, compiler::Assembler::kNearJump);
- __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::IntType()));
+ __ CompareObject(kTempReg, Type::ZoneHandle(zone(), Type::IntType()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(EDI, Type::ZoneHandle(zone(), Type::Number()));
+ __ CompareObject(kTempReg, Type::ZoneHandle(zone(), Type::Number()));
__ j(EQUAL, is_instance_lbl);
// Smi can be handled by type test cache.
__ Bind(¬_smi);
const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
- const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
- zone(), GenerateCallSubtypeTestStub(
- test_kind, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl));
- return type_test_cache.raw();
+ return GenerateCallSubtypeTestStub(test_kind, is_instance_lbl,
+ is_not_instance_lbl);
}
if (type.IsType()) {
// Smi is FutureOr<T>, when T is a top type or int or num.
@@ -502,11 +486,8 @@
compiler::Address(ESP, 0 * kWordSize));
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- return GenerateCallSubtypeTestStub(
- kTestTypeFourArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeFourArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -525,12 +506,8 @@
__ j(ZERO, is_not_instance_lbl);
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- const Register kTempReg = EDI;
- return GenerateCallSubtypeTestStub(
- kTestTypeSixArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeSixArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
// Inputs:
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 41e5961..80879b0 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -217,55 +217,6 @@
__ Bind(&fall_through);
}
-// Call stub to perform subtype test using a cache (see
-// stub_code_x64.cc:GenerateSubtypeNTestCacheStub)
-//
-// Inputs:
-// - RAX : instance to test against.
-// - RDX : instantiator type arguments (if necessary).
-// - RCX : function type arguments (if necessary).
-//
-// Preserves RAX/RCX/RDX.
-SubtypeTestCachePtr FlowGraphCompiler::GenerateCallSubtypeTestStub(
- TypeTestStubKind test_kind,
- Register instance_reg,
- Register instantiator_type_arguments_reg,
- Register function_type_arguments_reg,
- Register temp_reg,
- compiler::Label* is_instance_lbl,
- compiler::Label* is_not_instance_lbl) {
- ASSERT(temp_reg == kNoRegister);
- const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New());
- __ LoadUniqueObject(R9, type_test_cache);
- if (test_kind == kTestTypeOneArg) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ Call(StubCode::Subtype1TestCache());
- } else if (test_kind == kTestTypeTwoArgs) {
- ASSERT(instantiator_type_arguments_reg == kNoRegister);
- ASSERT(function_type_arguments_reg == kNoRegister);
- __ Call(StubCode::Subtype2TestCache());
- } else if (test_kind == kTestTypeFourArgs) {
- ASSERT(instantiator_type_arguments_reg ==
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- ASSERT(function_type_arguments_reg ==
- TypeTestABI::kFunctionTypeArgumentsReg);
- __ Call(StubCode::Subtype4TestCache());
- } else if (test_kind == kTestTypeSixArgs) {
- ASSERT(instantiator_type_arguments_reg ==
- TypeTestABI::kInstantiatorTypeArgumentsReg);
- ASSERT(function_type_arguments_reg ==
- TypeTestABI::kFunctionTypeArgumentsReg);
- __ Call(StubCode::Subtype6TestCache());
- } else {
- UNREACHABLE();
- }
- // Result is in R8: null -> not found, otherwise Bool::True or Bool::False.
- GenerateBoolToJump(R8, is_instance_lbl, is_not_instance_lbl);
- return type_test_cache.raw();
-}
-
// Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
// type test is conclusive, otherwise fallthrough if a type test could not
// be completed.
@@ -324,13 +275,8 @@
}
// Regular subtype test cache involving instance's type arguments.
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = kNoRegister;
- return GenerateCallSubtypeTestStub(
- kTestTypeTwoArgs, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
@@ -448,29 +394,24 @@
__ j(EQUAL, is_instance_lbl);
}
- const Register kInstantiatorTypeArgumentsReg = kNoRegister;
- const Register kFunctionTypeArgumentsReg = kNoRegister;
- const Register kTempReg = kNoRegister;
- return GenerateCallSubtypeTestStub(kTestTypeOneArg, TypeTestABI::kInstanceReg,
- kInstantiatorTypeArgumentsReg,
- kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeOneArg, is_instance_lbl,
+ is_not_instance_lbl);
}
// Generates inlined check if 'type' is a type parameter or type itself
//
-// Inputs:
-// - RAX : instance to test against.
-// - RDX : instantiator type arguments (if necessary).
-// - RCX : function type arguments (if necessary).
+// Inputs (from TypeTestABI):
+// - kInstanceReg : instance to test against.
+// - kInstantiatorTypeArgumentsReg : instantiator type arguments
+// (if necessary).
+// - kFunctionTypeArgumentsReg : function type arguments (if necessary).
//
-// Preserves RAX/RCX/RDX.
+// Preserves all input registers.
SubtypeTestCachePtr FlowGraphCompiler::GenerateUninstantiatedTypeTest(
TokenPosition token_pos,
const AbstractType& type,
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl) {
- const Register kTempReg = kNoRegister;
__ Comment("UninstantiatedTypeTest");
ASSERT(!type.IsInstantiated());
ASSERT(!type.IsFunctionType());
@@ -485,39 +426,39 @@
// Check if type arguments are null, i.e. equivalent to vector of dynamic.
__ CompareObject(kTypeArgumentsReg, Object::null_object());
__ j(EQUAL, is_instance_lbl);
- __ movq(RDI, compiler::FieldAddress(
- kTypeArgumentsReg,
- TypeArguments::type_at_offset(type_param.index())));
+ __ movq(TypeTestABI::kScratchReg,
+ compiler::FieldAddress(
+ kTypeArgumentsReg,
+ TypeArguments::type_at_offset(type_param.index())));
// RDI: Concrete type of type.
// Check if type argument is dynamic, Object?, or void.
- __ CompareObject(RDI, Object::dynamic_type());
+ __ CompareObject(TypeTestABI::kScratchReg, Object::dynamic_type());
__ j(EQUAL, is_instance_lbl);
__ CompareObject(
- RDI, Type::ZoneHandle(
- zone(), isolate()->object_store()->nullable_object_type()));
+ TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(),
+ isolate()->object_store()->nullable_object_type()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(RDI, Object::void_type());
+ __ CompareObject(TypeTestABI::kScratchReg, Object::void_type());
__ j(EQUAL, is_instance_lbl);
// For Smi check quickly against int and num interfaces.
compiler::Label not_smi;
- __ testq(RAX, compiler::Immediate(kSmiTagMask)); // Value is Smi?
+ __ testq(TypeTestABI::kInstanceReg,
+ compiler::Immediate(kSmiTagMask)); // Value is Smi?
__ j(NOT_ZERO, ¬_smi, compiler::Assembler::kNearJump);
- __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType()));
+ __ CompareObject(TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(), Type::IntType()));
__ j(EQUAL, is_instance_lbl);
- __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number()));
+ __ CompareObject(TypeTestABI::kScratchReg,
+ Type::ZoneHandle(zone(), Type::Number()));
__ j(EQUAL, is_instance_lbl);
// Smi can be handled by type test cache.
__ Bind(¬_smi);
const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
- const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
- zone(), GenerateCallSubtypeTestStub(
- test_kind, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg,
- is_instance_lbl, is_not_instance_lbl));
- return type_test_cache.raw();
+ return GenerateCallSubtypeTestStub(test_kind, is_instance_lbl,
+ is_not_instance_lbl);
}
if (type.IsType()) {
// Smi is FutureOr<T>, when T is a top type or int or num.
@@ -528,11 +469,8 @@
}
// Uninstantiated type class is known at compile time, but the type
// arguments are determined at runtime by the instantiator(s).
- return GenerateCallSubtypeTestStub(
- kTestTypeFourArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeFourArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -545,16 +483,12 @@
const AbstractType& type,
compiler::Label* is_instance_lbl,
compiler::Label* is_not_instance_lbl) {
- const Register kTempReg = kNoRegister;
__ Comment("FunctionTypeTest");
__ testq(TypeTestABI::kInstanceReg, compiler::Immediate(kSmiTagMask));
__ j(ZERO, is_not_instance_lbl);
- return GenerateCallSubtypeTestStub(
- kTestTypeSixArgs, TypeTestABI::kInstanceReg,
- TypeTestABI::kInstantiatorTypeArgumentsReg,
- TypeTestABI::kFunctionTypeArgumentsReg, kTempReg, is_instance_lbl,
- is_not_instance_lbl);
+ return GenerateCallSubtypeTestStub(kTestTypeSixArgs, is_instance_lbl,
+ is_not_instance_lbl);
}
// Inputs:
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 5c28b56..b6bd0e6 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -3338,20 +3338,9 @@
TypeParameterHelper helper(helper_);
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kBound);
- // TODO(github.com/dart-lang/kernel/issues/42): This should be handled
- // by the frontend.
parameter ^= type_parameters.TypeAt(i);
- const Tag tag = helper_->PeekTag(); // peek ith bound type.
- if (tag == kDynamicType) {
- helper_->SkipDartType(); // read ith bound.
- parameter.set_bound(
- Type::Handle(Z, nnbd_mode == NNBDMode::kOptedInLib
- ? I->object_store()->nullable_object_type()
- : I->object_store()->legacy_object_type()));
- } else {
- AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound.
- parameter.set_bound(bound);
- }
+ AbstractType& bound = BuildTypeWithoutFinalization(); // read ith bound.
+ parameter.set_bound(bound);
helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
const AbstractType* default_arg = &Object::dynamic_type();
if (helper_->ReadTag() == kSomething) {
diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc
index 4376d54..d1bb15d 100644
--- a/runtime/vm/compiler/stub_code_compiler.cc
+++ b/runtime/vm/compiler/stub_code_compiler.cc
@@ -183,7 +183,7 @@
__ PushRegister(TypeTestABI::kSubtypeTestCacheReg);
__ CallRuntime(kInstanceofRuntimeEntry, /*argument_count=*/5);
__ Drop(5);
- __ PopRegister(TypeTestABI::kResultReg);
+ __ PopRegister(TypeTestABI::kInstanceOfResultReg);
__ LeaveStubFrame();
__ Ret();
}
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 141f378..0b759e0 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -2617,41 +2617,52 @@
}
// Used to check class and type arguments. Arguments passed in registers:
-// LR: return address.
-// R0: instance (must be preserved).
-// R2: instantiator type arguments (only if n >= 4, can be raw_null).
-// R1: function type arguments (only if n >= 4, can be raw_null).
-// R3: target::SubtypeTestCache.
//
-// Preserves R0/R2.
-// Preserves NOTFP with bare instructions and CODE_REG without.
+// Inputs (mostly from TypeTestABI struct):
+// - kSubtypeTestCacheReg: SubtypeTestCacheLayout
+// - kInstanceReg: instance to test against (must be preserved).
+// - kInstantiatorTypeArgumentsReg: instantiator type arguments (for n=4).
+// - kFunctionTypeArgumentsReg: function type arguments (for n=4).
+// - LR: return address.
//
-// Result in R1: null -> not found, otherwise result (true or false).
+// All TypeTestABI registers are preserved but kSubtypeTestCacheReg and
+// kDstTypeReg, which must be saved by the caller if the original value is
+// needed after the call.
+//
+// Result in SubtypeTestCacheReg::kResultReg: null -> not found, otherwise
+// result (true or false).
static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
ASSERT(n == 1 || n == 2 || n == 4 || n == 6);
- const Register kInstanceCidOrFunction = R8;
- const Register kInstanceInstantiatorTypeArgumentsReg = R4;
- const Register kInstanceDelayedFunctionTypeArgumentsReg = PP;
+ // Safe as the original value of TypeTestABI::kSubtypeTestCacheReg is only
+ // used to initialize this register.
+ const Register kCacheArrayReg = TypeTestABI::kSubtypeTestCacheReg;
+ const Register kScratchReg = TypeTestABI::kScratchReg;
+ const Register kInstanceCidOrFunction = TypeTestABI::kDstTypeReg;
+ const Register kInstanceInstantiatorTypeArgumentsReg = R9;
+ // Registers that are only used for n >= 6 and must be preserved if used.
+ Register kInstanceParentFunctionTypeArgumentsReg = kNoRegister;
+ Register kInstanceDelayedFunctionTypeArgumentsReg = kNoRegister;
- Register kInstanceParentFunctionTypeArgumentsReg;
- Register kNullReg;
- if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
- // NOTFP must be preserved, but CODE_REG can be freely used.
- kInstanceParentFunctionTypeArgumentsReg = NOTFP;
- kNullReg = CODE_REG;
- } else {
- // CODE_REG must be preserved, but NOTFP can be freely used.
- kInstanceParentFunctionTypeArgumentsReg = CODE_REG;
- kNullReg = NOTFP;
- }
-
+ // NOTFP must be preserved for bare payloads, otherwise CODE_REG.
+ const bool use_bare_payloads =
+ FLAG_precompiled_mode && FLAG_use_bare_instructions;
+ // For this, we choose the register that need not be preserved of the pair.
+ const Register kNullReg = use_bare_payloads ? CODE_REG : NOTFP;
__ LoadObject(kNullReg, NullObject());
+ RegList pushed_registers = 0;
// Free up these 2 registers to be used for 6-value test.
if (n >= 6) {
- __ PushList(1 << kInstanceParentFunctionTypeArgumentsReg |
- 1 << kInstanceDelayedFunctionTypeArgumentsReg);
+ // For this, we choose the register that must be preserved of the pair.
+ kInstanceParentFunctionTypeArgumentsReg =
+ use_bare_payloads ? NOTFP : CODE_REG;
+ kInstanceDelayedFunctionTypeArgumentsReg = PP;
+ pushed_registers |= 1 << kInstanceParentFunctionTypeArgumentsReg |
+ 1 << kInstanceDelayedFunctionTypeArgumentsReg;
+ }
+ if (pushed_registers != 0) {
+ __ PushList(pushed_registers);
}
// Loop initialization (moved up here to avoid having all dependent loads
@@ -2659,10 +2670,10 @@
// We avoid a load-acquire barrier here by relying on the fact that all other
// loads from the array are data-dependent loads.
- __ ldr(TypeTestABI::kSubtypeTestCacheReg,
+ __ ldr(kCacheArrayReg,
FieldAddress(TypeTestABI::kSubtypeTestCacheReg,
target::SubtypeTestCache::cache_offset()));
- __ AddImmediate(TypeTestABI::kSubtypeTestCacheReg,
+ __ AddImmediate(kCacheArrayReg,
target::Array::data_offset() - kHeapObjectTag);
Label loop, not_closure;
@@ -2702,16 +2713,19 @@
__ Bind(¬_closure);
if (n >= 2) {
Label has_no_type_arguments;
- __ LoadClassById(R9, kInstanceCidOrFunction);
+ __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
__ mov(kInstanceInstantiatorTypeArgumentsReg, Operand(kNullReg));
- __ ldr(R9,
- FieldAddress(
- R9, target::Class::
- host_type_arguments_field_offset_in_words_offset()));
- __ CompareImmediate(R9, target::Class::kNoTypeArguments);
+ __ ldr(
+ kScratchReg,
+ FieldAddress(kScratchReg,
+ target::Class::
+ host_type_arguments_field_offset_in_words_offset()));
+ __ CompareImmediate(kScratchReg, target::Class::kNoTypeArguments);
__ b(&has_no_type_arguments, EQ);
- __ add(R9, TypeTestABI::kInstanceReg, Operand(R9, LSL, 2));
- __ ldr(kInstanceInstantiatorTypeArgumentsReg, FieldAddress(R9, 0));
+ __ add(kScratchReg, TypeTestABI::kInstanceReg,
+ Operand(kScratchReg, LSL, 2));
+ __ ldr(kInstanceInstantiatorTypeArgumentsReg,
+ FieldAddress(kScratchReg, 0));
__ Bind(&has_no_type_arguments);
if (n >= 6) {
@@ -2726,77 +2740,80 @@
// Loop header.
__ Bind(&loop);
- __ ldr(R9, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::kInstanceClassIdOrFunction));
- __ cmp(R9, Operand(kNullReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceClassIdOrFunction));
+ __ cmp(kScratchReg, Operand(kNullReg));
__ b(¬_found, EQ);
- __ cmp(R9, Operand(kInstanceCidOrFunction));
+ __ cmp(kScratchReg, Operand(kInstanceCidOrFunction));
if (n == 1) {
__ b(&found, EQ);
} else {
__ b(&next_iteration, NE);
- __ ldr(R9, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::kInstanceTypeArguments));
- __ cmp(R9, Operand(kInstanceInstantiatorTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceTypeArguments));
+ __ cmp(kScratchReg, Operand(kInstanceInstantiatorTypeArgumentsReg));
if (n == 2) {
__ b(&found, EQ);
} else {
__ b(&next_iteration, NE);
- __ ldr(R9,
- Address(TypeTestABI::kSubtypeTestCacheReg,
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
target::kWordSize *
target::SubtypeTestCache::kInstantiatorTypeArguments));
- __ cmp(R9, Operand(TypeTestABI::kInstantiatorTypeArgumentsReg));
+ __ cmp(kScratchReg, Operand(TypeTestABI::kInstantiatorTypeArgumentsReg));
__ b(&next_iteration, NE);
- __ ldr(R9, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::kFunctionTypeArguments));
- __ cmp(R9, Operand(TypeTestABI::kFunctionTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kFunctionTypeArguments));
+ __ cmp(kScratchReg, Operand(TypeTestABI::kFunctionTypeArgumentsReg));
if (n == 4) {
__ b(&found, EQ);
} else {
ASSERT(n == 6);
__ b(&next_iteration, NE);
- __ ldr(R9, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::
- kInstanceParentFunctionTypeArguments));
- __ cmp(R9, Operand(kInstanceParentFunctionTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceParentFunctionTypeArguments));
+ __ cmp(kScratchReg, Operand(kInstanceParentFunctionTypeArgumentsReg));
__ b(&next_iteration, NE);
- __ ldr(R9, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::
- kInstanceDelayedFunctionTypeArguments));
- __ cmp(R9, Operand(kInstanceDelayedFunctionTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceDelayedFunctionTypeArguments));
+ __ cmp(kScratchReg, Operand(kInstanceDelayedFunctionTypeArgumentsReg));
__ b(&found, EQ);
}
}
}
__ Bind(&next_iteration);
__ AddImmediate(
- TypeTestABI::kSubtypeTestCacheReg,
+ kCacheArrayReg,
target::kWordSize * target::SubtypeTestCache::kTestEntryLength);
__ b(&loop);
__ Bind(&found);
- __ ldr(R1,
- Address(TypeTestABI::kSubtypeTestCacheReg,
+ __ ldr(TypeTestABI::kSubtypeTestCacheResultReg,
+ Address(kCacheArrayReg,
target::kWordSize * target::SubtypeTestCache::kTestResult));
- if (n >= 6) {
- __ PopList(1 << kInstanceParentFunctionTypeArgumentsReg |
- 1 << kInstanceDelayedFunctionTypeArgumentsReg);
+ if (pushed_registers != 0) {
+ __ PopList(pushed_registers);
}
__ Ret();
__ Bind(¬_found);
- __ mov(R1, Operand(kNullReg));
- if (n >= 6) {
- __ PopList(1 << kInstanceParentFunctionTypeArgumentsReg |
- 1 << kInstanceDelayedFunctionTypeArgumentsReg);
+ __ mov(TypeTestABI::kSubtypeTestCacheResultReg, Operand(kNullReg));
+ if (pushed_registers != 0) {
+ __ PopList(pushed_registers);
}
__ Ret();
}
@@ -2821,20 +2838,22 @@
GenerateSubtypeNTestCacheStub(assembler, 6);
}
-// Used to test whether a given value is of a given type (different variants,
-// all have the same calling convention).
+// The <X>TypeTestStubs are used to test whether a given value is of a given
+// type. All variants have the same calling convention:
//
-// Inputs:
-// - R0 : instance to test against.
-// - R2 : instantiator type arguments (if needed).
-// - R1 : function type arguments (if needed).
+// Inputs (from TypeTestABI struct):
+// - kSubtypeTestCacheReg: RawSubtypeTestCache
+// - kInstanceReg: instance to test against.
+// - kInstantiatorTypeArgumentsReg : instantiator type arguments (if needed).
+// - kFunctionTypeArgumentsReg : function type arguments (if needed).
//
-// - R3 : subtype test cache.
+// See GenerateSubtypeNTestCacheStub for registers that may need saving by the
+// caller.
//
-// - R8 : type to test against.
-// - R4 : name of destination variable.
+// Output (from TypeTestABI struct):
+// - kResultReg: checked instance.
//
-// Preserves R0/R2.
+// Throws if the check is unsuccessful.
//
// Note of warning: The caller will not populate CODE_REG and we have therefore
// no access to the pool.
@@ -2982,25 +3001,25 @@
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
__ BranchIf(EQUAL, &call_runtime);
- const Register kTmp = R9;
-
// If this is not a [Type] object, we'll go to the runtime.
Label is_simple_case, is_complex_case;
- __ LoadClassId(kTmp, TypeTestABI::kDstTypeReg);
- __ cmp(kTmp, Operand(kTypeCid));
+ __ LoadClassId(TypeTestABI::kScratchReg, TypeTestABI::kDstTypeReg);
+ __ cmp(TypeTestABI::kScratchReg, Operand(kTypeCid));
__ BranchIf(NOT_EQUAL, &is_complex_case);
// Check whether this [Type] is instantiated/uninstantiated.
- __ ldrb(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
- target::Type::type_state_offset()));
- __ cmp(kTmp,
+ __ ldrb(TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg,
+ target::Type::type_state_offset()));
+ __ cmp(TypeTestABI::kScratchReg,
Operand(target::AbstractTypeLayout::kTypeStateFinalizedInstantiated));
__ BranchIf(NOT_EQUAL, &is_complex_case);
// Check whether this [Type] is a function type.
- __ ldr(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
- target::Type::signature_offset()));
- __ CompareObject(kTmp, NullObject());
+ __ ldr(
+ TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg, target::Type::signature_offset()));
+ __ CompareObject(TypeTestABI::kScratchReg, NullObject());
__ BranchIf(NOT_EQUAL, &is_complex_case);
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
@@ -3009,14 +3028,14 @@
// Fall through to &is_simple_case
const intptr_t kRegsToSave = (1 << TypeTestABI::kSubtypeTestCacheReg) |
- (1 << TypeTestABI::kDstTypeReg) |
- (1 << TypeTestABI::kFunctionTypeArgumentsReg);
+ (1 << TypeTestABI::kDstTypeReg);
__ Bind(&is_simple_case);
{
__ PushList(kRegsToSave);
__ BranchLink(StubCodeSubtype2TestCache());
- __ CompareObject(R1, CastHandle<Object>(TrueObject()));
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
__ PopList(kRegsToSave);
__ BranchIf(EQUAL, &done); // Cache said: yes.
__ Jump(&call_runtime);
@@ -3026,7 +3045,8 @@
{
__ PushList(kRegsToSave);
__ BranchLink(StubCodeSubtype6TestCache());
- __ CompareObject(R1, CastHandle<Object>(TrueObject()));
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
__ PopList(kRegsToSave);
__ BranchIf(EQUAL, &done); // Cache said: yes.
// Fall through to runtime_call
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index b749ad9..d64b50d 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -2786,36 +2786,47 @@
}
// Used to check class and type arguments. Arguments passed in registers:
-// LR: return address.
-// R0: instance (must be preserved).
-// R2: instantiator type arguments (only if n == 4, can be raw_null).
-// R1: function type arguments (only if n == 4, can be raw_null).
-// R3: target::SubtypeTestCache.
//
-// Preserves R0/R2/R8.
+// Inputs (mostly from TypeTestABI struct):
+// - kSubtypeTestCacheReg: SubtypeTestCacheLayout
+// - kInstanceReg: instance to test against.
+// - kInstantiatorTypeArgumentsReg: instantiator type arguments (for n=4).
+// - kFunctionTypeArgumentsReg: function type arguments (for n=4).
+// - LR: return address.
//
-// Result in R1: null -> not found, otherwise result (true or false).
+// All input registers are preserved except for kSubtypeTestCacheReg, which
+// should be saved by the caller if needed.
+//
+// Result in SubtypeTestCacheReg::kResultReg: null -> not found, otherwise
+// result (true or false).
static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
ASSERT(n == 1 || n == 2 || n == 4 || n == 6);
+ // Until we have the result, we use the result register to store the null
+ // value for quick access. This has the side benefit of initializing the
+ // result to null, so it only needs to be changed if found.
+ const Register kNullReg = TypeTestABI::kSubtypeTestCacheResultReg;
+ __ LoadObject(kNullReg, NullObject());
+
+ const Register kCacheArrayReg = TypeTestABI::kSubtypeTestCacheReg;
+ const Register kScratchReg = TypeTestABI::kScratchReg;
const Register kInstanceCidOrFunction = R6;
- const Register kInstanceInstantiatorTypeArgumentsReg = R4;
+ const Register kInstanceInstantiatorTypeArgumentsReg = R5;
const Register kInstanceParentFunctionTypeArgumentsReg = R9;
const Register kInstanceDelayedFunctionTypeArgumentsReg = R10;
- const Register kNullReg = R7;
-
- __ LoadObject(kNullReg, NullObject());
+ // All of these must be distinct from TypeTestABI::kSubtypeTestCacheResultReg
+ // since it is used for kNullReg as well.
// Loop initialization (moved up here to avoid having all dependent loads
// after each other).
// We avoid a load-acquire barrier here by relying on the fact that all other
// loads from the array are data-dependent loads.
- __ ldr(TypeTestABI::kSubtypeTestCacheReg,
+ __ ldr(kCacheArrayReg,
FieldAddress(TypeTestABI::kSubtypeTestCacheReg,
target::SubtypeTestCache::cache_offset()));
- __ AddImmediate(TypeTestABI::kSubtypeTestCacheReg,
+ __ AddImmediate(kCacheArrayReg,
target::Array::data_offset() - kHeapObjectTag);
Label loop, not_closure;
@@ -2856,16 +2867,18 @@
__ Bind(¬_closure);
if (n >= 2) {
Label has_no_type_arguments;
- __ LoadClassById(R5, kInstanceCidOrFunction);
+ __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
__ mov(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
__ LoadFieldFromOffset(
- R5, R5,
+ kScratchReg, kScratchReg,
target::Class::host_type_arguments_field_offset_in_words_offset(),
kWord);
- __ CompareImmediate(R5, target::Class::kNoTypeArguments);
+ __ CompareImmediate(kScratchReg, target::Class::kNoTypeArguments);
__ b(&has_no_type_arguments, EQ);
- __ add(R5, TypeTestABI::kInstanceReg, Operand(R5, LSL, 3));
- __ ldr(kInstanceInstantiatorTypeArgumentsReg, FieldAddress(R5, 0));
+ __ add(kScratchReg, TypeTestABI::kInstanceReg,
+ Operand(kScratchReg, LSL, 3));
+ __ ldr(kInstanceInstantiatorTypeArgumentsReg,
+ FieldAddress(kScratchReg, 0));
__ Bind(&has_no_type_arguments);
if (n >= 6) {
@@ -2876,74 +2889,76 @@
__ SmiTag(kInstanceCidOrFunction);
}
- Label found, not_found, next_iteration;
+ Label found, done, next_iteration;
// Loop header
__ Bind(&loop);
- __ ldr(R5, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::kInstanceClassIdOrFunction));
- __ cmp(R5, Operand(kNullReg));
- __ b(¬_found, EQ);
- __ cmp(R5, Operand(kInstanceCidOrFunction));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceClassIdOrFunction));
+ __ cmp(kScratchReg, Operand(kNullReg));
+ __ b(&done, EQ);
+ __ cmp(kScratchReg, Operand(kInstanceCidOrFunction));
if (n == 1) {
__ b(&found, EQ);
} else {
__ b(&next_iteration, NE);
- __ ldr(R5, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::kInstanceTypeArguments));
- __ cmp(R5, Operand(kInstanceInstantiatorTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceTypeArguments));
+ __ cmp(kScratchReg, Operand(kInstanceInstantiatorTypeArgumentsReg));
if (n == 2) {
__ b(&found, EQ);
} else {
__ b(&next_iteration, NE);
- __ ldr(R5,
- Address(TypeTestABI::kSubtypeTestCacheReg,
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
target::kWordSize *
target::SubtypeTestCache::kInstantiatorTypeArguments));
- __ cmp(R5, Operand(TypeTestABI::kInstantiatorTypeArgumentsReg));
+ __ cmp(kScratchReg, Operand(TypeTestABI::kInstantiatorTypeArgumentsReg));
__ b(&next_iteration, NE);
- __ ldr(R5, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::kFunctionTypeArguments));
- __ cmp(R5, Operand(TypeTestABI::kFunctionTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kFunctionTypeArguments));
+ __ cmp(kScratchReg, Operand(TypeTestABI::kFunctionTypeArgumentsReg));
if (n == 4) {
__ b(&found, EQ);
} else {
ASSERT(n == 6);
__ b(&next_iteration, NE);
- __ ldr(R5, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::
- kInstanceParentFunctionTypeArguments));
- __ cmp(R5, Operand(kInstanceParentFunctionTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceParentFunctionTypeArguments));
+ __ cmp(kScratchReg, Operand(kInstanceParentFunctionTypeArgumentsReg));
__ b(&next_iteration, NE);
- __ ldr(R5, Address(TypeTestABI::kSubtypeTestCacheReg,
- target::kWordSize *
- target::SubtypeTestCache::
- kInstanceDelayedFunctionTypeArguments));
- __ cmp(R5, Operand(kInstanceDelayedFunctionTypeArgumentsReg));
+ __ ldr(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceDelayedFunctionTypeArguments));
+ __ cmp(kScratchReg, Operand(kInstanceDelayedFunctionTypeArgumentsReg));
__ b(&found, EQ);
}
}
}
__ Bind(&next_iteration);
__ AddImmediate(
- TypeTestABI::kSubtypeTestCacheReg,
+ kCacheArrayReg,
target::kWordSize * target::SubtypeTestCache::kTestEntryLength);
__ b(&loop);
__ Bind(&found);
- __ ldr(R1,
- Address(TypeTestABI::kSubtypeTestCacheReg,
+ __ ldr(TypeTestABI::kSubtypeTestCacheResultReg,
+ Address(kCacheArrayReg,
target::kWordSize * target::SubtypeTestCache::kTestResult));
- __ ret();
-
- __ Bind(¬_found);
- __ mov(R1, kNullReg);
+ __ Bind(&done);
__ ret();
}
@@ -2967,20 +2982,22 @@
GenerateSubtypeNTestCacheStub(assembler, 6);
}
-// Used to test whether a given value is of a given type (different variants,
-// all have the same calling convention).
+// The <X>TypeTestStubs are used to test whether a given value is of a given
+// type. All variants have the same calling convention:
//
-// Inputs:
-// - R0 : instance to test against.
-// - R2 : instantiator type arguments (if needed).
-// - R1 : function type arguments (if needed).
+// Inputs (from TypeTestABI struct):
+// - kSubtypeTestCacheReg: RawSubtypeTestCache
+// - kInstanceReg: instance to test against.
+// - kInstantiatorTypeArgumentsReg : instantiator type arguments (if needed).
+// - kFunctionTypeArgumentsReg : function type arguments (if needed).
//
-// - R3 : subtype test cache.
+// See GenerateSubtypeNTestCacheStub for registers that may need saving by the
+// caller.
//
-// - R8 : type to test against.
-// - R4 : name of destination variable.
+// Output (from TypeTestABI struct):
+// - kResultReg: checked instance.
//
-// Preserves R0/R2.
+// Throws if the check is unsuccessful.
//
// Note of warning: The caller will not populate CODE_REG and we have therefore
// no access to the pool.
@@ -3136,27 +3153,26 @@
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
__ BranchIf(EQUAL, &call_runtime);
- const Register kTmp = R9;
-
// If this is not a [Type] object, we'll go to the runtime.
Label is_simple_case, is_complex_case;
- __ LoadClassId(kTmp, TypeTestABI::kDstTypeReg);
- __ cmp(kTmp, Operand(kTypeCid));
+ __ LoadClassId(TypeTestABI::kScratchReg, TypeTestABI::kDstTypeReg);
+ __ cmp(TypeTestABI::kScratchReg, Operand(kTypeCid));
__ BranchIf(NOT_EQUAL, &is_complex_case);
// Check whether this [Type] is instantiated/uninstantiated.
- __ ldr(kTmp,
+ __ ldr(TypeTestABI::kScratchReg,
FieldAddress(TypeTestABI::kDstTypeReg,
target::Type::type_state_offset(), kByte),
kByte);
- __ cmp(kTmp,
+ __ cmp(TypeTestABI::kScratchReg,
Operand(target::AbstractTypeLayout::kTypeStateFinalizedInstantiated));
__ BranchIf(NOT_EQUAL, &is_complex_case);
// Check whether this [Type] is a function type.
- __ ldr(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
- target::Type::signature_offset()));
- __ CompareObject(kTmp, NullObject());
+ __ ldr(
+ TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg, target::Type::signature_offset()));
+ __ CompareObject(TypeTestABI::kScratchReg, NullObject());
__ BranchIf(NOT_EQUAL, &is_complex_case);
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
@@ -3169,7 +3185,8 @@
__ PushPair(TypeTestABI::kFunctionTypeArgumentsReg,
TypeTestABI::kSubtypeTestCacheReg);
__ BranchLink(StubCodeSubtype2TestCache());
- __ CompareObject(R1, CastHandle<Object>(TrueObject()));
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
__ PopPair(TypeTestABI::kFunctionTypeArgumentsReg,
TypeTestABI::kSubtypeTestCacheReg);
__ BranchIf(EQUAL, &done); // Cache said: yes.
@@ -3181,7 +3198,8 @@
__ PushPair(TypeTestABI::kFunctionTypeArgumentsReg,
TypeTestABI::kSubtypeTestCacheReg);
__ BranchLink(StubCodeSubtype6TestCache());
- __ CompareObject(R1, CastHandle<Object>(TrueObject()));
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
__ PopPair(TypeTestABI::kFunctionTypeArgumentsReg,
TypeTestABI::kSubtypeTestCacheReg);
__ BranchIf(EQUAL, &done); // Cache said: yes.
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index bc4c545..efc4e36 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -2186,29 +2186,69 @@
// TOS + 2: instantiator type arguments (only if n == 4, can be raw_null).
// TOS + 3: instance.
// TOS + 4: SubtypeTestCache.
-// Result in ECX: null -> not found, otherwise result (true or false).
+//
+// No registers are preserved by this stub.
+//
+// Result in SubtypeTestCacheReg::kResultReg: null -> not found, otherwise
+// result (true or false).
static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
ASSERT(n == 1 || n == 2 || n == 4 || n == 6);
- static intptr_t kFunctionTypeArgumentsInBytes = 1 * target::kWordSize;
- static intptr_t kInstantiatorTypeArgumentsInBytes = 2 * target::kWordSize;
- static intptr_t kInstanceOffsetInBytes = 3 * target::kWordSize;
- static intptr_t kCacheOffsetInBytes = 4 * target::kWordSize;
+ // We represent the depth of as a depth from the top of the stack at the
+ // start of the stub. That is, depths for input values are non-negative and
+ // depths for values pushed during the stub are negative.
- const Register kInstanceCidOrFunction = ECX;
- const Register kInstanceInstantiatorTypeArgumentsReg = EBX;
+ // Used to initialize depths for conditionally-pushed values.
+ const intptr_t kNoDepth = kIntptrMin;
+ // Offset of the original top of the stack from the current top of stack.
+ intptr_t original_tos_offset = 0;
+
+ // Inputs use relative depths.
+ static constexpr intptr_t kFunctionTypeArgumentsDepth = 1;
+ static constexpr intptr_t kInstantiatorTypeArgumentsDepth = 2;
+ static constexpr intptr_t kInstanceDepth = 3;
+ static constexpr intptr_t kCacheDepth = 4;
+ // Others use absolute depths. We initialize conditionally pushed values to
+ // kNoInput for extra checking.
+ intptr_t kInstanceParentFunctionTypeArgumentsDepth = kNoDepth;
+ intptr_t kInstanceDelayedFunctionTypeArgumentsDepth = kNoDepth;
+
+ // Other values are stored in non-kInstanceReg registers from TypeTestABI.
+ const Register kCacheArrayReg = TypeTestABI::kInstantiatorTypeArgumentsReg;
+ const Register kScratchReg = TypeTestABI::kSubtypeTestCacheReg;
+ const Register kInstanceCidOrFunction =
+ TypeTestABI::kFunctionTypeArgumentsReg;
+ const Register kInstanceInstantiatorTypeArgumentsReg =
+ TypeTestABI::kDstTypeReg;
+
+ // Loads a value at the given depth from the stack into dst.
+ auto load_from_stack = [&](Register dst, intptr_t depth) {
+ ASSERT(depth != kNoDepth);
+ __ movl(dst,
+ Address(ESP, (original_tos_offset + depth) * target::kWordSize));
+ };
+
+ // Compares a value at the given depth from the stack to the value in src.
+ auto compare_to_stack = [&](Register src, intptr_t depth) {
+ ASSERT(depth != kNoDepth);
+ __ cmpl(src,
+ Address(ESP, (original_tos_offset + depth) * target::kWordSize));
+ };
const auto& raw_null = Immediate(target::ToRawPointer(NullObject()));
- __ movl(TypeTestABI::kInstanceReg, Address(ESP, kInstanceOffsetInBytes));
+ load_from_stack(TypeTestABI::kInstanceReg, kInstanceDepth);
// Loop initialization (moved up here to avoid having all dependent loads
// after each other)
- __ movl(EDX, Address(ESP, kCacheOffsetInBytes));
+ load_from_stack(kCacheArrayReg, kCacheDepth);
// We avoid a load-acquire barrier here by relying on the fact that all other
// loads from the array are data-dependent loads.
- __ movl(EDX, FieldAddress(EDX, target::SubtypeTestCache::cache_offset()));
- __ addl(EDX, Immediate(target::Array::data_offset() - kHeapObjectTag));
+ __ movl(
+ kCacheArrayReg,
+ FieldAddress(kCacheArrayReg, target::SubtypeTestCache::cache_offset()));
+ __ addl(kCacheArrayReg,
+ Immediate(target::Array::data_offset() - kHeapObjectTag));
Label loop, not_closure;
if (n >= 4) {
@@ -2246,16 +2286,17 @@
__ Bind(¬_closure);
if (n >= 2) {
Label has_no_type_arguments;
- __ LoadClassById(EDI, kInstanceCidOrFunction);
+ __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
__ movl(kInstanceInstantiatorTypeArgumentsReg, raw_null);
- __ movl(EDI,
- FieldAddress(
- EDI, target::Class::
+ __ movl(
+ kScratchReg,
+ FieldAddress(kScratchReg,
+ target::Class::
host_type_arguments_field_offset_in_words_offset()));
- __ cmpl(EDI, Immediate(target::Class::kNoTypeArguments));
+ __ cmpl(kScratchReg, Immediate(target::Class::kNoTypeArguments));
__ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump);
__ movl(kInstanceInstantiatorTypeArgumentsReg,
- FieldAddress(TypeTestABI::kInstanceReg, EDI, TIMES_4, 0));
+ FieldAddress(TypeTestABI::kInstanceReg, kScratchReg, TIMES_4, 0));
__ Bind(&has_no_type_arguments);
if (n >= 6) {
@@ -2266,84 +2307,91 @@
__ SmiTag(kInstanceCidOrFunction);
}
- const intptr_t kInstanceParentFunctionTypeArgumentsFromSp = 0;
- const intptr_t kInstanceDelayedFunctionTypeArgumentsFromSp =
- target::kWordSize;
- const intptr_t args_offset = n >= 6 ? 2 * target::kWordSize : 0;
+ if (n >= 6) {
+ // Now that instance handling is done, both the delayed and parent function
+ // type arguments stack slots have been set, so any input uses must be
+ // offset by the new values and the new values can now be accessed in
+ // the following code without issue when n >= 6.
+ original_tos_offset = 2;
+ kInstanceDelayedFunctionTypeArgumentsDepth = -1;
+ kInstanceParentFunctionTypeArgumentsDepth = -2;
+ }
- Label found, not_found, next_iteration;
+ Label done, next_iteration;
// Loop header.
__ Bind(&loop);
- __ movl(
- EDI,
- Address(EDX, target::kWordSize *
- target::SubtypeTestCache::kInstanceClassIdOrFunction));
- __ cmpl(EDI, raw_null);
- __ j(EQUAL, ¬_found, Assembler::kNearJump);
- __ cmpl(EDI, kInstanceCidOrFunction);
+ __ movl(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceClassIdOrFunction));
+ __ cmpl(kScratchReg, raw_null);
+ __ j(EQUAL, &done, Assembler::kNearJump);
+ __ cmpl(kScratchReg, kInstanceCidOrFunction);
if (n == 1) {
- __ j(EQUAL, &found, Assembler::kNearJump);
+ __ j(EQUAL, &done, Assembler::kNearJump);
} else {
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
__ cmpl(kInstanceInstantiatorTypeArgumentsReg,
- Address(EDX, target::kWordSize *
- target::SubtypeTestCache::kInstanceTypeArguments));
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceTypeArguments));
if (n == 2) {
- __ j(EQUAL, &found, Assembler::kNearJump);
+ __ j(EQUAL, &done, Assembler::kNearJump);
} else {
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
__ movl(
- EDI,
- Address(EDX,
+ kScratchReg,
+ Address(kCacheArrayReg,
target::kWordSize *
target::SubtypeTestCache::kInstantiatorTypeArguments));
- __ cmpl(EDI,
- Address(ESP, args_offset + kInstantiatorTypeArgumentsInBytes));
+ compare_to_stack(kScratchReg, kInstantiatorTypeArgumentsDepth);
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
- __ movl(
- EDI,
- Address(EDX, target::kWordSize *
- target::SubtypeTestCache::kFunctionTypeArguments));
- __ cmpl(EDI, Address(ESP, args_offset + kFunctionTypeArgumentsInBytes));
+ __ movl(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kFunctionTypeArguments));
+ compare_to_stack(kScratchReg, kFunctionTypeArgumentsDepth);
if (n == 4) {
- __ j(EQUAL, &found, Assembler::kNearJump);
+ __ j(EQUAL, &done, Assembler::kNearJump);
} else {
ASSERT(n == 6);
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
- __ movl(EDI,
- Address(EDX, target::kWordSize *
- target::SubtypeTestCache::
- kInstanceParentFunctionTypeArguments));
- __ cmpl(EDI, Address(ESP, kInstanceParentFunctionTypeArgumentsFromSp));
+ __ movl(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceParentFunctionTypeArguments));
+ compare_to_stack(kScratchReg,
+ kInstanceParentFunctionTypeArgumentsDepth);
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
- __ movl(EDI,
- Address(EDX, target::kWordSize *
- target::SubtypeTestCache::
- kInstanceDelayedFunctionTypeArguments));
- __ cmpl(EDI, Address(ESP, kInstanceDelayedFunctionTypeArgumentsFromSp));
- __ j(EQUAL, &found, Assembler::kNearJump);
+ __ movl(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceDelayedFunctionTypeArguments));
+ compare_to_stack(kScratchReg,
+ kInstanceDelayedFunctionTypeArgumentsDepth);
+ __ j(EQUAL, &done, Assembler::kNearJump);
}
}
}
__ Bind(&next_iteration);
- __ addl(EDX, Immediate(target::kWordSize *
- target::SubtypeTestCache::kTestEntryLength));
+ __ addl(kCacheArrayReg,
+ Immediate(target::kWordSize *
+ target::SubtypeTestCache::kTestEntryLength));
__ jmp(&loop, Assembler::kNearJump);
- __ Bind(&found);
- __ movl(ECX, Address(EDX, target::kWordSize *
- target::SubtypeTestCache::kTestResult));
- if (n == 6) {
+ __ Bind(&done);
+ // In the not found case, the test result slot is null, so we can
+ // unconditionally load from the cache entry.
+ __ movl(TypeTestABI::kSubtypeTestCacheResultReg,
+ Address(kCacheArrayReg,
+ target::kWordSize * target::SubtypeTestCache::kTestResult));
+ if (n >= 6) {
__ Drop(2);
- }
- __ ret();
-
- __ Bind(¬_found);
- __ movl(ECX, raw_null);
- if (n == 6) {
- __ Drop(2);
+ original_tos_offset = 0; // In case we add any input uses after this point.
}
__ ret();
}
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index b3c99af..676714f 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -2732,31 +2732,41 @@
// Used to check class and type arguments. Arguments passed in registers:
//
-// Inputs:
-// - R9 : RawSubtypeTestCache
-// - RAX : instance to test against.
-// - RDX : instantiator type arguments (for n=4).
-// - RCX : function type arguments (for n=4).
-//
+// Input registers (from TypeTestABI struct):
+// - kSubtypeTestCacheReg: SubtypeTestCacheLayout
+// - kInstanceReg: instance to test against (must be preserved).
+// - kInstantiatorTypeArgumentsReg: instantiator type arguments (for n>=4).
+// - kFunctionTypeArgumentsReg: function type arguments (for n>=4).
+// Inputs from stack:
// - TOS + 0: return address.
//
-// Preserves R9/RAX/RCX/RDX, RBX.
+// All input registers are preserved.
//
-// Result in R8: null -> not found, otherwise result (true or false).
+// Result in SubtypeTestCacheReg::kResultReg: null -> not found, otherwise
+// result (true or false).
static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
ASSERT(n == 1 || n == 2 || n == 4 || n == 6);
+ // Until we have the result, we use the result register to store the null
+ // value for quick access. This has the side benefit of initializing the
+ // result to null, so it only needs to be changed if found.
+ const Register kNullReg = TypeTestABI::kSubtypeTestCacheResultReg;
+ __ LoadObject(kNullReg, NullObject());
+
+ // All of these must be distinct from TypeTestABI::kSubtypeTestCacheResultReg
+ // since it is used for kNullReg as well.
+ const Register kCacheArrayReg = RDI;
+ const Register kScratchReg = TypeTestABI::kScratchReg;
const Register kInstanceCidOrFunction = R10;
const Register kInstanceInstantiatorTypeArgumentsReg = R13;
- const Register kInstanceParentFunctionTypeArgumentsReg = PP;
- const Register kInstanceDelayedFunctionTypeArgumentsReg = CODE_REG;
-
- const Register kNullReg = R8;
-
- __ LoadObject(kNullReg, NullObject());
+ // Only used for n >= 6, so set conditionally in that case to catch misuse.
+ Register kInstanceParentFunctionTypeArgumentsReg = kNoRegister;
+ Register kInstanceDelayedFunctionTypeArgumentsReg = kNoRegister;
// Free up these 2 registers to be used for 6-value test.
if (n >= 6) {
+ kInstanceParentFunctionTypeArgumentsReg = PP;
+ kInstanceDelayedFunctionTypeArgumentsReg = CODE_REG;
__ pushq(kInstanceParentFunctionTypeArgumentsReg);
__ pushq(kInstanceDelayedFunctionTypeArgumentsReg);
}
@@ -2766,9 +2776,11 @@
// We avoid a load-acquire barrier here by relying on the fact that all other
// loads from the array are data-dependent loads.
- __ movq(RSI, FieldAddress(TypeTestABI::kSubtypeTestCacheReg,
- target::SubtypeTestCache::cache_offset()));
- __ addq(RSI, Immediate(target::Array::data_offset() - kHeapObjectTag));
+ __ movq(kCacheArrayReg,
+ FieldAddress(TypeTestABI::kSubtypeTestCacheReg,
+ target::SubtypeTestCache::cache_offset()));
+ __ addq(kCacheArrayReg,
+ Immediate(target::Array::data_offset() - kHeapObjectTag));
Label loop, not_closure;
if (n >= 4) {
@@ -2808,16 +2820,17 @@
__ Bind(¬_closure);
if (n >= 2) {
Label has_no_type_arguments;
- __ LoadClassById(RDI, kInstanceCidOrFunction);
+ __ LoadClassById(kScratchReg, kInstanceCidOrFunction);
__ movq(kInstanceInstantiatorTypeArgumentsReg, kNullReg);
- __ movl(RDI,
- FieldAddress(
- RDI, target::Class::
+ __ movl(
+ kScratchReg,
+ FieldAddress(kScratchReg,
+ target::Class::
host_type_arguments_field_offset_in_words_offset()));
- __ cmpl(RDI, Immediate(target::Class::kNoTypeArguments));
+ __ cmpl(kScratchReg, Immediate(target::Class::kNoTypeArguments));
__ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump);
__ movq(kInstanceInstantiatorTypeArgumentsReg,
- FieldAddress(TypeTestABI::kInstanceReg, RDI, TIMES_8, 0));
+ FieldAddress(TypeTestABI::kInstanceReg, kScratchReg, TIMES_8, 0));
__ Bind(&has_no_type_arguments);
if (n >= 6) {
@@ -2832,34 +2845,35 @@
// Loop header.
__ Bind(&loop);
- __ movq(
- RDI,
- Address(RSI, target::kWordSize *
- target::SubtypeTestCache::kInstanceClassIdOrFunction));
- __ cmpq(RDI, kNullReg);
+ __ movq(kScratchReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceClassIdOrFunction));
+ __ cmpq(kScratchReg, kNullReg);
__ j(EQUAL, ¬_found, Assembler::kNearJump);
- __ cmpq(RDI, kInstanceCidOrFunction);
+ __ cmpq(kScratchReg, kInstanceCidOrFunction);
if (n == 1) {
__ j(EQUAL, &found, Assembler::kNearJump);
} else {
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
__ cmpq(kInstanceInstantiatorTypeArgumentsReg,
- Address(RSI, target::kWordSize *
- target::SubtypeTestCache::kInstanceTypeArguments));
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kInstanceTypeArguments));
if (n == 2) {
__ j(EQUAL, &found, Assembler::kNearJump);
} else {
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
__ cmpq(
TypeTestABI::kInstantiatorTypeArgumentsReg,
- Address(RSI,
+ Address(kCacheArrayReg,
target::kWordSize *
target::SubtypeTestCache::kInstantiatorTypeArguments));
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
- __ cmpq(
- TypeTestABI::kFunctionTypeArgumentsReg,
- Address(RSI, target::kWordSize *
- target::SubtypeTestCache::kFunctionTypeArguments));
+ __ cmpq(TypeTestABI::kFunctionTypeArgumentsReg,
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::kFunctionTypeArguments));
if (n == 4) {
__ j(EQUAL, &found, Assembler::kNearJump);
@@ -2868,32 +2882,31 @@
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
__ cmpq(kInstanceParentFunctionTypeArgumentsReg,
- Address(RSI, target::kWordSize *
- target::SubtypeTestCache::
- kInstanceParentFunctionTypeArguments));
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceParentFunctionTypeArguments));
__ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump);
__ cmpq(kInstanceDelayedFunctionTypeArgumentsReg,
- Address(RSI, target::kWordSize *
- target::SubtypeTestCache::
- kInstanceDelayedFunctionTypeArguments));
+ Address(kCacheArrayReg,
+ target::kWordSize *
+ target::SubtypeTestCache::
+ kInstanceDelayedFunctionTypeArguments));
__ j(EQUAL, &found, Assembler::kNearJump);
}
}
}
__ Bind(&next_iteration);
- __ addq(RSI, Immediate(target::kWordSize *
- target::SubtypeTestCache::kTestEntryLength));
+ __ addq(kCacheArrayReg,
+ Immediate(target::kWordSize *
+ target::SubtypeTestCache::kTestEntryLength));
__ jmp(&loop, Assembler::kNearJump);
__ Bind(&found);
- __ movq(R8, Address(RSI, target::kWordSize *
- target::SubtypeTestCache::kTestResult));
- if (n >= 6) {
- __ popq(kInstanceDelayedFunctionTypeArgumentsReg);
- __ popq(kInstanceParentFunctionTypeArgumentsReg);
- }
- __ ret();
+ __ movq(TypeTestABI::kSubtypeTestCacheResultReg,
+ Address(kCacheArrayReg,
+ target::kWordSize * target::SubtypeTestCache::kTestResult));
__ Bind(¬_found);
if (n >= 6) {
@@ -2923,19 +2936,22 @@
GenerateSubtypeNTestCacheStub(assembler, 6);
}
-// Used to test whether a given value is of a given type (different variants,
-// all have the same calling convention).
+// The <X>TypeTestStubs are used to test whether a given value is of a given
+// type. All variants have the same calling convention:
//
-// Inputs:
-// - R9 : RawSubtypeTestCache
-// - RAX : instance to test against.
-// - RDX : instantiator type arguments (if needed).
-// - RCX : function type arguments (if needed).
+// Inputs (from TypeTestABI struct):
+// - kSubtypeTestCacheReg: RawSubtypeTestCache
+// - kInstanceReg: instance to test against.
+// - kInstantiatorTypeArgumentsReg : instantiator type arguments (if needed).
+// - kFunctionTypeArgumentsReg : function type arguments (if needed).
//
-// - RBX : type to test against.
-// - R10 : name of destination variable.
+// See GenerateSubtypeNTestCacheStub for registers that may need saving by the
+// caller.
//
-// Preserves R9/RAX/RCX/RDX, RBX, R10.
+// Output (from TypeTestABI struct):
+// - kResultReg: checked instance.
+//
+// Throws if the check is unsuccessful.
//
// Note of warning: The caller will not populate CODE_REG and we have therefore
// no access to the pool.
@@ -3083,12 +3099,10 @@
__ CompareObject(TypeTestABI::kSubtypeTestCacheReg, NullObject());
__ BranchIf(EQUAL, &call_runtime);
- const Register kTmp = RDI;
-
// If this is not a [Type] object, we'll go to the runtime.
Label is_simple_case, is_complex_case;
- __ LoadClassId(kTmp, TypeTestABI::kDstTypeReg);
- __ cmpq(kTmp, Immediate(kTypeCid));
+ __ LoadClassId(TypeTestABI::kScratchReg, TypeTestABI::kDstTypeReg);
+ __ cmpq(TypeTestABI::kScratchReg, Immediate(kTypeCid));
__ BranchIf(NOT_EQUAL, &is_complex_case);
// Check whether this [Type] is instantiated/uninstantiated.
@@ -3098,9 +3112,10 @@
__ BranchIf(NOT_EQUAL, &is_complex_case);
// Check whether this [Type] is a function type.
- __ movq(kTmp, FieldAddress(TypeTestABI::kDstTypeReg,
- target::Type::signature_offset()));
- __ CompareObject(kTmp, NullObject());
+ __ movq(
+ TypeTestABI::kScratchReg,
+ FieldAddress(TypeTestABI::kDstTypeReg, target::Type::signature_offset()));
+ __ CompareObject(TypeTestABI::kScratchReg, NullObject());
__ BranchIf(NOT_EQUAL, &is_complex_case);
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
@@ -3111,7 +3126,8 @@
__ Bind(&is_simple_case);
{
__ Call(StubCodeSubtype2TestCache());
- __ CompareObject(R8, CastHandle<Object>(TrueObject()));
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
__ BranchIf(EQUAL, &done); // Cache said: yes.
__ Jump(&call_runtime);
}
@@ -3119,7 +3135,8 @@
__ Bind(&is_complex_case);
{
__ Call(StubCodeSubtype6TestCache());
- __ CompareObject(R8, CastHandle<Object>(TrueObject()));
+ __ CompareObject(TypeTestABI::kSubtypeTestCacheResultReg,
+ CastHandle<Object>(TrueObject()));
__ BranchIf(EQUAL, &done); // Cache said: yes.
// Fall through to runtime_call
}
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 016d438..23b16b3 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -333,13 +333,16 @@
static const Register kSubtypeTestCacheReg = R3;
static const Register kScratchReg = R4;
+ // For calls to InstanceOfStub.
+ static const Register kInstanceOfResultReg = kInstanceReg;
+ // For calls to SubtypeNTestCacheStub. Must be saved by the caller if the
+ // original value is needed after the call.
+ static const Register kSubtypeTestCacheResultReg = kSubtypeTestCacheReg;
+
static const intptr_t kAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
(1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
-
- // For call to InstanceOfStub.
- static const Register kResultReg = R0;
};
// Calling convention when calling AssertSubtypeStub.
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 39225df..21319ca 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -165,13 +165,17 @@
static const Register kSubtypeTestCacheReg = R3;
static const Register kScratchReg = R4;
+ // For calls to InstanceOfStub.
+ static const Register kInstanceOfResultReg = kInstanceReg;
+ // For calls to SubtypeNTestCacheStub. Must not overlap with any other
+ // registers above, for it is also used internally as kNullReg in those stubs.
+ static const Register kSubtypeTestCacheResultReg = R7;
+
static const intptr_t kAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
- (1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
-
- // For call to InstanceOfStub.
- static const Register kResultReg = R0;
+ (1 << kSubtypeTestCacheReg) | (1 << kScratchReg) |
+ (1 << kSubtypeTestCacheResultReg);
};
// Calling convention when calling AssertSubtypeStub.
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index a8d5b46..94db1e2 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -118,7 +118,10 @@
EDI; // On ia32 we don't use CODE_REG.
// For call to InstanceOfStub.
- static const Register kResultReg = kNoRegister;
+ static const Register kInstanceOfResultReg = kNoRegister;
+ // For call to SubtypeNTestCacheStub.
+ static const Register kSubtypeTestCacheResultReg =
+ TypeTestABI::kSubtypeTestCacheReg;
};
// Calling convention when calling kSubtypeCheckRuntimeEntry, to match other
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index c1fb6c3..ae421fd 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -155,13 +155,17 @@
static const Register kSubtypeTestCacheReg = R9;
static const Register kScratchReg = RSI;
+ // For calls to InstanceOfStub.
+ static const Register kInstanceOfResultReg = kInstanceReg;
+ // For calls to SubtypeNTestCacheStub. Must not overlap with any other
+ // registers above, for it is also used internally as kNullReg in those stubs.
+ static const Register kSubtypeTestCacheResultReg = R8;
+
static const intptr_t kAbiRegisters =
(1 << kInstanceReg) | (1 << kDstTypeReg) |
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
- (1 << kSubtypeTestCacheReg) | (1 << kScratchReg);
-
- // For call to InstanceOfStub.
- static const Register kResultReg = RAX;
+ (1 << kSubtypeTestCacheReg) | (1 << kScratchReg) |
+ (1 << kSubtypeTestCacheResultReg);
};
// Calling convention when calling AssertSubtypeStub.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4776fa5..7c1e68c 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1590,6 +1590,9 @@
{
StackZone zone(T);
HandleScope handle_scope(T);
+#if defined(DEBUG)
+ I->ValidateConstants();
+#endif
Dart::RunShutdownCallback();
}
Dart::ShutdownIsolate();
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 5e02239..341b4fc 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -167,8 +167,6 @@
P(print_snapshot_sizes, bool, false, "Print sizes of generated snapshots.") \
P(print_snapshot_sizes_verbose, bool, false, \
"Print cluster sizes of generated snapshots.") \
- P(print_benchmarking_metrics, bool, false, \
- "Print additional memory and latency metrics for benchmarking.") \
R(print_ssa_liveranges, false, bool, false, \
"Print live ranges after allocation.") \
R(print_stacktrace_at_api_error, false, bool, false, \
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index ca08cac..914eaa9 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2068,6 +2068,11 @@
#endif // !PRODUCT
IsolateSpawnState* state = spawn_state();
if (state != nullptr) {
+ // If the embedder does not make the isolate runnable during the
+ // `create_isolate_group`/`initialize_isolate` embedder callbacks but rather
+ // some time in the future, we'll hit this case.
+ // WARNING: This is currently untested - we might consider changing our APIs
+ // to disallow two different flows.
ASSERT(this == state->isolate());
Run();
}
@@ -2086,15 +2091,6 @@
Service::HandleEvent(&runnableEvent);
}
GetRunnableLatencyMetric()->set_value(UptimeMicros());
- if (FLAG_print_benchmarking_metrics) {
- {
- StartIsolateScope scope(this);
- heap()->CollectAllGarbage();
- }
- int64_t heap_size = (heap()->UsedInWords(Heap::kNew) * kWordSize) +
- (heap()->UsedInWords(Heap::kOld) * kWordSize);
- GetRunnableHeapSizeMetric()->set_value(heap_size);
- }
#endif // !PRODUCT
return nullptr;
}
@@ -2404,27 +2400,8 @@
}
static void ShutdownIsolate(uword parameter) {
- Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
- {
- // Print the error if there is one. This may execute dart code to
- // print the exception object, so we need to use a StartIsolateScope.
- StartIsolateScope start_scope(isolate);
- Thread* thread = Thread::Current();
- ASSERT(thread->isolate() == isolate);
-
- // We must wait for any outstanding spawn calls to complete before
- // running the shutdown callback.
- isolate->WaitForOutstandingSpawns();
-
- StackZone zone(thread);
- HandleScope handle_scope(thread);
-#if defined(DEBUG)
- isolate->ValidateConstants();
-#endif // defined(DEBUG)
- Dart::RunShutdownCallback();
- }
- // Shut the isolate down.
- Dart::ShutdownIsolate(isolate);
+ Dart_EnterIsolate(reinterpret_cast<Dart_Isolate>(parameter));
+ Dart_ShutdownIsolate();
}
void Isolate::SetStickyError(ErrorPtr sticky_error) {
@@ -2548,7 +2525,7 @@
"\tisolate: %s\n",
name());
}
- if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) {
+ if (FLAG_print_metrics) {
LogBlock lb;
OS::PrintErr("Printing metrics for %s\n", name());
#define ISOLATE_GROUP_METRIC_PRINT(type, variable, name, unit) \
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index ecfda6c..f7e582b 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -206,7 +206,7 @@
}
void Metric::Cleanup() {
- if (FLAG_print_metrics || FLAG_print_benchmarking_metrics) {
+ if (FLAG_print_metrics) {
// Create a zone to allocate temporary strings in.
StackZone sz(Thread::Current());
OS::PrintErr("Printing metrics for VM\n");
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index e3a6b03..93bd80c 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -26,7 +26,9 @@
return new JSArray<E>.fixed(length);
}
- /// Returns a fresh JavaScript Array, marked as fixed-length.
+ /// Returns a fresh JavaScript Array, marked as fixed-length. The holes in the
+ /// array yield `undefined`, making the Dart List appear to be filled with
+ /// `null` values.
///
/// [length] must be a non-negative integer.
factory JSArray.fixed(int length) {
@@ -36,8 +38,34 @@
if (length is! int) {
throw new ArgumentError.value(length, 'length', 'is not an integer');
}
- // The JavaScript Array constructor with one argument throws if
- // the value is not a UInt32. Give a better error message.
+ // The JavaScript Array constructor with one argument throws if the value is
+ // not a UInt32 but the error message does not contain the bad value. Give a
+ // better error message.
+ int maxJSArrayLength = 0xFFFFFFFF;
+ if (length < 0 || length > maxJSArrayLength) {
+ throw new RangeError.range(length, 0, maxJSArrayLength, 'length');
+ }
+ return new JSArray<E>.markFixed(JS('', 'new Array(#)', length));
+ }
+
+ /// Returns a fresh JavaScript Array, marked as fixed-length. The Array is
+ /// allocated but no elements are assigned.
+ ///
+ /// All elements of the array must be assigned before the array is valid. This
+ /// is essentially the same as `JSArray.fixed` except that global type
+ /// inference starts with bottom for the element type.
+ ///
+ /// [length] must be a non-negative integer.
+ factory JSArray.allocateFixed(int length) {
+ // Explicit type test is necessary to guard against JavaScript conversions
+ // in unchecked mode, and against `new Array(null)` which creates a single
+ // element Array containing `null`.
+ if (length is! int) {
+ throw new ArgumentError.value(length, 'length', 'is not an integer');
+ }
+ // The JavaScript Array constructor with one argument throws if the value is
+ // not a UInt32 but the error message does not contain the bad value. Give a
+ // better error message.
int maxJSArrayLength = 0xFFFFFFFF;
if (length < 0 || length > maxJSArrayLength) {
throw new RangeError.range(length, 0, maxJSArrayLength, 'length');
@@ -48,9 +76,11 @@
/// Returns a fresh growable JavaScript Array of zero length length.
factory JSArray.emptyGrowable() => new JSArray<E>.markGrowable(JS('', '[]'));
- /// Returns a fresh growable JavaScript Array with initial length.
+ /// Returns a fresh growable JavaScript Array with initial length. The holes
+ /// in the array yield `undefined`, making the Dart List appear to be filled
+ /// with `null` values.
///
- /// [validatedLength] must be a non-negative integer.
+ /// [length] must be a non-negative integer.
factory JSArray.growable(int length) {
// Explicit type test is necessary to guard against JavaScript conversions
// in unchecked mode.
@@ -60,6 +90,23 @@
return new JSArray<E>.markGrowable(JS('', 'new Array(#)', length));
}
+ /// Returns a fresh growable JavaScript Array with initial length. The Array
+ /// is allocated but no elements are assigned.
+ ///
+ /// All elements of the array must be assigned before the array is valid. This
+ /// is essentially the same as `JSArray.growable` except that global type
+ /// inference starts with bottom for the element type.
+ ///
+ /// [length] must be a non-negative integer.
+ factory JSArray.allocateGrowable(int length) {
+ // Explicit type test is necessary to guard against JavaScript conversions
+ // in unchecked mode.
+ if ((length is! int) || (length < 0)) {
+ throw new ArgumentError('Length must be a non-negative integer: $length');
+ }
+ return new JSArray<E>.markGrowable(JS('', 'new Array(#)', length));
+ }
+
/// Constructor for adding type parameters to an existing JavaScript Array.
/// The compiler specially recognizes this constructor.
///
diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
index 16ab9b0..c6adb12 100644
--- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -209,9 +209,9 @@
}
String? namedGroup(String name) {
- var groups = JS('Object|Null', '#.groups', _match);
+ var groups = JS('=Object|Null', '#.groups', _match);
if (groups != null) {
- var result = JS('String|Null', '#[#]', groups, name);
+ String? result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS('bool', '# in #', name, groups)) {
return result;
}
@@ -220,7 +220,7 @@
}
Iterable<String> get groupNames {
- var groups = JS('Object|Null', '#.groups', _match);
+ var groups = JS('=Object|Null', '#.groups', _match);
if (groups != null) {
var keys = new JSArray<String>.markGrowable(
JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', groups));
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index c362eea..4db2a34 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -251,8 +251,7 @@
}
void addError(Object error, [StackTrace? stackTrace]) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
if (!_mayAddEvent) throw _addEventError();
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
@@ -486,8 +485,7 @@
}
void addError(Object error, [StackTrace? stackTrace]) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
stackTrace ??= AsyncError.defaultStackTrace(error);
if (!isClosed && _isFiring) {
_addPendingEvent(new _DelayedError(error, stackTrace));
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 0e1d703..0e92b2e 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -275,7 +275,7 @@
*/
factory Future.error(Object error, [StackTrace? stackTrace]) {
// TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
if (!identical(Zone.current, _rootZone)) {
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 4e24a48..0d38c61 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -18,7 +18,7 @@
void completeError(Object error, [StackTrace? stackTrace]) {
// TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
if (!future._mayComplete) throw new StateError("Future already completed");
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 150a759..60f4aa1 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -152,7 +152,7 @@
@Since("2.5")
factory Stream.error(Object error, [StackTrace? stackTrace]) {
// TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
return (_AsyncStreamController<T>(null, null, null, null)
.._addError(error, stackTrace ?? AsyncError.defaultStackTrace(error))
.._closeUnchecked())
@@ -2212,20 +2212,22 @@
}
/**
- * An [Iterator] like interface for the values of a [Stream].
+ * An [Iterator]-like interface for the values of a [Stream].
*
* This wraps a [Stream] and a subscription on the stream. It listens
* on the stream, and completes the future returned by [moveNext] when the
* next value becomes available.
*
* The stream may be paused between calls to [moveNext].
+ *
+ * The [current] value must only be used after a future returned by [moveNext]
+ * has completed with `true`, and only until [moveNext] is called again.
*/
abstract class StreamIterator<T> {
/** Create a [StreamIterator] on [stream]. */
- factory StreamIterator(Stream<T> stream)
+ factory StreamIterator(Stream<T> stream) =>
// TODO(lrn): use redirecting factory constructor when type
// arguments are supported.
- =>
new _StreamIterator<T>(stream);
/**
@@ -2247,14 +2249,16 @@
/**
* The current value of the stream.
*
- * Is `null` before the first call to [moveNext] and after a call to
- * `moveNext` completes with a `false` result or an error.
- *
- * When a `moveNext` call completes with `true`, the `current` field holds
+ * When a [moveNext] call completes with `true`, the [current] field holds
* the most recent event of the stream, and it stays like that until the next
- * call to `moveNext`.
- * Between a call to `moveNext` and when its returned future completes,
- * the value is unspecified.
+ * call to [moveNext]. This value must only be read after a call to [moveNext]
+ * has completed with `true`, and only until the [moveNext] is called again.
+ *
+ * If the StreamIterator has not yet been moved to the first element
+ * ([moveNext] has not been called and completed yet), or if the
+ * StreamIterator has been moved past the last element ([moveNext] has
+ * returned `false`), then [current] is unspecified. A [StreamIterator] may
+ * either throw or return an iterator-specific default value in that case.
*/
T get current;
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 4c3e4f9..dbaacc1 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -628,8 +628,7 @@
* Send or enqueue an error event.
*/
void addError(Object error, [StackTrace? stackTrace]) {
- // TODO(40614): Remove once non-nullability is sound. Use checkNotNullable.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
if (!_mayAddEvent) throw _badEventState();
AsyncError? replacement = Zone.current.errorCallback(error, stackTrace);
if (replacement != null) {
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 6ec5d03..bb4a1ba 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -1009,7 +1009,7 @@
bool _hasValue = false;
_StreamIterator(final Stream<T> stream)
- : _stateData = ArgumentError.checkNotNull(stream, "stream");
+ : _stateData = checkNotNullable(stream, "stream");
T get current {
if (_hasValue) return _stateData as dynamic;
diff --git a/sdk/lib/async/stream_transformers.dart b/sdk/lib/async/stream_transformers.dart
index ca7934c..aa99f5f 100644
--- a/sdk/lib/async/stream_transformers.dart
+++ b/sdk/lib/async/stream_transformers.dart
@@ -229,8 +229,7 @@
}
void addError(Object error, [StackTrace? stackTrace]) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
var sink = _sink;
if (sink == null) {
throw StateError("Sink is closed");
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index b4e3994..f662d53 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -36,16 +36,14 @@
typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
ZoneSpecification? specification, Map<Object?, Object?>? zoneValues);
-/** Pair of error and stack trace. Returned by [Zone.errorCallback]. */
+/// Pair of error and stack trace. Returned by [Zone.errorCallback].
class AsyncError implements Error {
final Object error;
final StackTrace stackTrace;
- AsyncError(this.error, StackTrace? stackTrace)
- : stackTrace = stackTrace ?? defaultStackTrace(error) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
- }
+ AsyncError(Object error, StackTrace? stackTrace)
+ : error = checkNotNullable(error, "error"),
+ stackTrace = stackTrace ?? defaultStackTrace(error);
/// A default stack trace for an error.
///
@@ -795,8 +793,7 @@
}
AsyncError? errorCallback(Zone zone, Object error, StackTrace? stackTrace) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
var implementation = _delegationTarget._errorCallback;
_Zone implZone = implementation.zone;
if (identical(implZone, _rootZone)) return null;
@@ -1130,8 +1127,7 @@
}
AsyncError? errorCallback(Object error, StackTrace? stackTrace) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
var implementation = this._errorCallback;
final _Zone implementationZone = implementation.zone;
if (identical(implementationZone, _rootZone)) return null;
@@ -1532,7 +1528,7 @@
{Map<Object?, Object?>? zoneValues,
ZoneSpecification? zoneSpecification,
@Deprecated("Use runZonedGuarded instead") Function? onError}) {
- ArgumentError.checkNotNull(body, "body");
+ checkNotNullable(body, "body");
if (onError != null) {
// TODO: Remove this when code have been migrated off using [onError].
if (onError is! void Function(Object, StackTrace)) {
@@ -1592,8 +1588,8 @@
@Since("2.8")
R? runZonedGuarded<R>(R body(), void onError(Object error, StackTrace stack),
{Map<Object?, Object?>? zoneValues, ZoneSpecification? zoneSpecification}) {
- ArgumentError.checkNotNull(body, "body");
- ArgumentError.checkNotNull(onError, "onError");
+ checkNotNullable(body, "body");
+ checkNotNullable(onError, "onError");
_Zone parentZone = Zone._current;
HandleUncaughtErrorHandler errorHandler = (Zone self, ZoneDelegate parent,
Zone zone, Object error, StackTrace stackTrace) {
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index 17f84a2..9e697a5 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -197,7 +197,7 @@
}
E elementAt(int index) {
- ArgumentError.checkNotNull(index, "index");
+ checkNotNullable(index, "index");
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
for (E element in this) {
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 045bbd5..327a7ea 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -523,7 +523,7 @@
}
void insert(int index, E element) {
- ArgumentError.checkNotNull(index, "index");
+ checkNotNullable(index, "index");
var length = this.length;
RangeError.checkValueInInterval(index, 0, length, "index");
add(element);
diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart
index 0a6ccbf..5cd75d6 100644
--- a/sdk/lib/collection/set.dart
+++ b/sdk/lib/collection/set.dart
@@ -268,7 +268,7 @@
}
E elementAt(int index) {
- ArgumentError.checkNotNull(index, "index");
+ checkNotNullable(index, "index");
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
for (E element in this) {
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index d2c24f0..19a8561 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.dart
@@ -73,8 +73,7 @@
}
void addError(Object error, [StackTrace? stackTrace]) {
- // TODO(40614): Remove once non-nullability is sound.
- ArgumentError.checkNotNull(error, "error");
+ checkNotNullable(error, "error");
_eventSink.addError(error, stackTrace);
}
diff --git a/sdk/lib/convert/convert.dart b/sdk/lib/convert/convert.dart
index 6173782..1ea3d26 100644
--- a/sdk/lib/convert/convert.dart
+++ b/sdk/lib/convert/convert.dart
@@ -55,7 +55,7 @@
import 'dart:async';
import 'dart:typed_data';
-import 'dart:_internal' show CastConverter, parseHexByte;
+import 'dart:_internal' show CastConverter, checkNotNullable, parseHexByte;
part 'ascii.dart';
part 'base64.dart';
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index aa85fcc..e8c9dcb 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -394,7 +394,7 @@
"DateTime is outside valid range: $millisecondsSinceEpoch");
}
// For backwards compatibility with legacy mode.
- ArgumentError.checkNotNull(isUtc, "isUtc");
+ checkNotNullable(isUtc, "isUtc");
}
/**
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 839792e..7482058 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -170,7 +170,7 @@
Iterable<R> cast<R>() => Iterable.castFrom<E, R>(this);
/**
- * Returns the lazy concatentation of this iterable and [other].
+ * Returns the lazy concatenation of this iterable and [other].
*
* The returned iterable will provide the same elements as this iterable,
* and, after that, the elements of [other], in the same order as in the
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 8970fe8..32c17f0 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -43,6 +43,12 @@
LanguageFeatures/Subtyping/static/tests/left_bottom_A01_t02: Skip # Type aliases are not supported by analyzer
LanguageFeatures/Subtyping/static/tests/left_bottom_A01_t04: Skip # Type aliases are not supported by analyzer
LanguageFeatures/Subtyping/static/tests/left_bottom_A01_t06: Skip # Type aliases are not supported by analyzer
+LanguageFeatures/nnbd/Least-greatest-closure/nonfunction_typedef/nonfunction_dynamic_t01: Skip # Type aliases are not fully supported by analyzer yet
+LanguageFeatures/nnbd/Least-greatest-closure/nonfunction_typedef/nonfunction_dynamic_t02: Skip # Type aliases are not fully supported by analyzer yet
+LanguageFeatures/nnbd/Least-greatest-closure/nonfunction_typedef/nonfunction_dynamic_t03: Skip # Type aliases are not fully supported by analyzer yet
+LanguageFeatures/nnbd/Least-greatest-closure/nonfunction_typedef/nonfunction_static_t01: Skip # Type aliases are not fully supported by analyzer yet
+LanguageFeatures/nnbd/Least-greatest-closure/nonfunction_typedef/nonfunction_static_t02: Skip # Type aliases are not fully supported by analyzer yet
+LanguageFeatures/nnbd/Least-greatest-closure/nonfunction_typedef/nonfunction_static_t03: Skip # Type aliases are not fully supported by analyzer yet
[ $compiler == fasta ]
Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t10: Skip # Type aliases are not fully implemented
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 6bb5259..1fe42fe 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -21,6 +21,23 @@
Language/Libraries_and_Scripts/Scripts/main_optional_parameters_t03: SkipByDesign # https://github.com/dart-lang/co19/issues/952
Language/Metadata/before*: Skip # dart:mirrors not supported https://github.com/dart-lang/co19/issues/523.
Language/Reference/Operator_Precedence/precedence_15_unary_prefix_t08: SkipByDesign # binary '~' produces different results in JavaScript and Dart
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A01_t01: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A01_t02: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A01_t03: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A02_t01: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A02_t04: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A03_t01: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A03_t02: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A03_t03: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A03_t04: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A03_t06: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A04_t01: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A04_t02: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A05_t01: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A05_t02: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/static_analysis_external_A05_t03: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/syntax_A01_t03: SkipByDesign # External variables are not supported by dart2js
+LanguageFeatures/Abstract-external-fields/syntax_A02_t03: SkipByDesign # External variables are not supported by dart2js
LibTest/core/DateTime/DateTime.fromMicrosecondsSinceEpoch_A01_t01: SkipByDesign # microseconds are not supported in JavaScript
LibTest/core/DateTime/microsecond_A01_t01: SkipByDesign # microseconds are not supported in JavaScript
LibTest/core/DateTime/microsecondsSinceEpoch_A01_t01: SkipByDesign # microseconds are not supported in JavaScript
diff --git a/tests/dart2js/list_generate_1_test.dart b/tests/dart2js/list_generate_1_test.dart
new file mode 100644
index 0000000..1b2fb4d
--- /dev/null
+++ b/tests/dart2js/list_generate_1_test.dart
@@ -0,0 +1,69 @@
+// 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';
+
+dynamic function = 'function';
+dynamic growable = 'growable';
+dynamic length = 'length';
+
+// Use top level dynamic variables so this call is not lowered. This function
+// and the callers (test1, test2) are not inlined to prevent store-forwarding of
+// the top-level variables.
+@pragma('dart2js:noInline')
+List<T> general<T>() => List<T>.generate(length, function, growable: growable);
+
+void main() {
+ function = (int i) => i;
+ growable = true;
+ length = 5;
+
+ test1();
+
+ int k = 0;
+ function = (int u) => seq3(u += 10, k += 100, () => u += k + 100000);
+ growable = false;
+ length = 5;
+
+ test2();
+}
+
+@pragma('dart2js:noInline')
+void test1() {
+ // Simple test.
+ final r1 = List<num>.generate(5, (i) => i, growable: true);
+ final r2 = general<num>();
+
+ Expect.equals('[0, 1, 2, 3, 4]', '$r1');
+ Expect.equals('[0, 1, 2, 3, 4]', '$r2');
+}
+
+// A sequence of two operations in expression form, returning the last value.
+T seq2<T>(dynamic a, T b) => b;
+T seq3<T>(dynamic a, dynamic b, T c) => c;
+
+@pragma('dart2js:noInline')
+void test2() {
+ // Test with a complex environment.
+ int c = 0;
+ final r1 = List<int Function()>.generate(
+ 5,
+ (i) => seq3(i += 10, c += 100, () => i += c + 100000),
+ growable: false,
+ );
+ final r2 = general<int Function()>();
+
+ final e12 = r1[2];
+ final e22 = r2[2];
+
+ final s123 = [e12(), e12(), e12()];
+ final s223 = [e22(), e22(), e22()];
+
+ // 'i' is bound to the loop variable (2 for element at [2]).
+ // 'i' is incremented by 10, so the low digits are '12'
+ // 'c' is shared by all closures, and has been incremented to 500 at end of
+ // construction, so each call increments 'i' by 100500.
+ Expect.equals('[100512, 201012, 301512]', '$s123');
+ Expect.equals('[100512, 201012, 301512]', '$s123');
+}
diff --git a/tests/dart2js/list_generate_2_test.dart b/tests/dart2js/list_generate_2_test.dart
new file mode 100644
index 0000000..83487e5
--- /dev/null
+++ b/tests/dart2js/list_generate_2_test.dart
@@ -0,0 +1,21 @@
+// 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';
+
+void main() {
+ test(0, '[]');
+ test(1, '[[[1]]]');
+ test(2, '[[[1]], [[2], [3, 4]]]');
+ test(3, '[[[1]], [[2], [3, 4]], [[5], [6, 7], [8, 9, 10]]]');
+}
+
+void test(int i, String expected) {
+ // Many nested closures with shadowing variables.
+ int c = 0;
+ final r = List.generate(
+ i, (i) => List.generate(i + 1, (i) => List.generate(i + 1, (i) => ++c)));
+
+ Expect.equals(expected, '$r');
+}
diff --git a/tests/language/regress/regress44136_test.dart b/tests/language/regress/regress44136_test.dart
new file mode 100644
index 0000000..99dfa35
--- /dev/null
+++ b/tests/language/regress/regress44136_test.dart
@@ -0,0 +1,12 @@
+// 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";
+
+typedef Foo = void Function<X extends dynamic>();
+typedef Bar = void Function<X extends Object?>();
+
+void main() {
+ Expect.notEquals(Foo, Bar);
+}
diff --git a/tests/language_2/regress/regress44136_test.dart b/tests/language_2/regress/regress44136_test.dart
new file mode 100644
index 0000000..8478fc5
--- /dev/null
+++ b/tests/language_2/regress/regress44136_test.dart
@@ -0,0 +1,12 @@
+// 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";
+
+typedef Foo = void Function<X extends dynamic>();
+typedef Bar = void Function<X extends Object>();
+
+void main() {
+ Expect.notEquals(Foo, Bar);
+}
diff --git a/tests/lib/async/future_error_test.dart b/tests/lib/async/future_error_test.dart
index 760c392..47f0f15 100644
--- a/tests/lib/async/future_error_test.dart
+++ b/tests/lib/async/future_error_test.dart
@@ -8,7 +8,7 @@
main() {
// The error cannot be null.
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
Future.error(null as dynamic);
});
}
diff --git a/tests/lib/async/stream_controller_add_error_test.dart b/tests/lib/async/stream_controller_add_error_test.dart
index f195fef..aea9294 100644
--- a/tests/lib/async/stream_controller_add_error_test.dart
+++ b/tests/lib/async/stream_controller_add_error_test.dart
@@ -9,41 +9,41 @@
main() {
// Single-cast async.
var controller = StreamController();
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.addError(null as dynamic);
});
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null as dynamic);
});
// Single-cast sync.
controller = StreamController(sync: true);
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.addError(null as dynamic);
});
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null as dynamic);
});
// Broadcast async.
controller = StreamController.broadcast();
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.addError(null as dynamic);
});
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null as dynamic);
});
// Broadcast sync.
controller = StreamController.broadcast(sync: true);
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.addError(null as dynamic);
});
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null as dynamic);
});
}
diff --git a/tests/lib/async/zone_async_error_test.dart b/tests/lib/async/zone_async_error_test.dart
index ca6c87c..1d3bf04 100644
--- a/tests/lib/async/zone_async_error_test.dart
+++ b/tests/lib/async/zone_async_error_test.dart
@@ -8,7 +8,7 @@
main() {
// The error cannot be null.
- Expect.throwsNullCheckError(() {
+ Expect.throwsTypeError(() {
AsyncError(null as dynamic, StackTrace.current);
});
}
diff --git a/tests/lib/js/extends_test/extends_subtyping_test.dart b/tests/lib/js/extends_test/extends_subtyping_test.dart
new file mode 100644
index 0000000..76dc51e
--- /dev/null
+++ b/tests/lib/js/extends_test/extends_subtyping_test.dart
@@ -0,0 +1,10 @@
+// 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 'extends_test_util.dart';
+
+void main() {
+ setUpWithoutES6Syntax();
+ testSubtyping();
+}
diff --git a/tests/lib/js/extends_test/extends_test.dart b/tests/lib/js/extends_test/extends_test.dart
index 12f8e3f..a9c8781 100644
--- a/tests/lib/js/extends_test/extends_test.dart
+++ b/tests/lib/js/extends_test/extends_test.dart
@@ -5,53 +5,6 @@
import 'extends_test_util.dart';
void main() {
- // Use the old way to define inheritance between JS objects.
- eval(r"""
- function inherits(child, parent) {
- if (child.prototype.__proto__) {
- child.prototype.__proto__ = parent.prototype;
- } else {
- function tmp() {};
- tmp.prototype = parent.prototype;
- child.prototype = new tmp();
- child.prototype.constructor = child;
- }
- }
- function JSClass(a) {
- this.a = a;
- this.getA = function() {
- return this.a;
- }
- this.getAOrB = function() {
- return this.getA();
- }
- }
- function JSExtendJSClass(a, b) {
- JSClass.call(this, a);
- this.b = b;
- this.getB = function() {
- return this.b;
- }
- this.getAOrB = function() {
- return this.getB();
- }
- }
- inherits(JSExtendJSClass, JSClass);
- function JSExtendAnonymousClass(a, b) {
- this.a = a;
- this.b = b;
- this.getA = function() {
- return this.a;
- }
- this.getB = function() {
- return this.b;
- }
- this.getAOrB = function() {
- return this.getB();
- }
- }
- self.anonExtendAnon = new JSExtendAnonymousClass(1, 2);
- self.anonExtendJS = new JSExtendJSClass(1, 2);
- """);
+ setUpWithoutES6Syntax();
testInheritance();
}
diff --git a/tests/lib/js/extends_test/extends_test_util.dart b/tests/lib/js/extends_test/extends_test_util.dart
index 5185176..e39e1b9 100644
--- a/tests/lib/js/extends_test/extends_test_util.dart
+++ b/tests/lib/js/extends_test/extends_test_util.dart
@@ -60,6 +60,108 @@
external AnonymousExtendAnonymousClass get anonExtendAnon;
external AnonymousExtendJSClass get anonExtendJS;
+void useJSClass(JSClass js) {}
+void useAnonymousClass(AnonymousClass a) {}
+
+void setUpWithoutES6Syntax() {
+ // Use the old way to define inheritance between JS objects.
+ eval(r"""
+ function inherits(child, parent) {
+ if (child.prototype.__proto__) {
+ child.prototype.__proto__ = parent.prototype;
+ } else {
+ function tmp() {};
+ tmp.prototype = parent.prototype;
+ child.prototype = new tmp();
+ child.prototype.constructor = child;
+ }
+ }
+ function JSClass(a) {
+ this.a = a;
+ this.getA = function() {
+ return this.a;
+ }
+ this.getAOrB = function() {
+ return this.getA();
+ }
+ }
+ function JSExtendJSClass(a, b) {
+ JSClass.call(this, a);
+ this.b = b;
+ this.getB = function() {
+ return this.b;
+ }
+ this.getAOrB = function() {
+ return this.getB();
+ }
+ }
+ inherits(JSExtendJSClass, JSClass);
+ function JSExtendAnonymousClass(a, b) {
+ this.a = a;
+ this.b = b;
+ this.getA = function() {
+ return this.a;
+ }
+ this.getB = function() {
+ return this.b;
+ }
+ this.getAOrB = function() {
+ return this.getB();
+ }
+ }
+ self.anonExtendAnon = new JSExtendAnonymousClass(1, 2);
+ self.anonExtendJS = new JSExtendJSClass(1, 2);
+ """);
+}
+
+void setUpWithES6Syntax() {
+ // Use the ES6 syntax for classes to make inheritance easier.
+ eval(r"""
+ class JSClass {
+ constructor(a) {
+ this.a = a;
+ }
+ getA() {
+ return this.a;
+ }
+ getAOrB() {
+ return this.getA();
+ }
+ }
+ class JSExtendJSClass extends JSClass {
+ constructor(a, b) {
+ super(a);
+ this.b = b;
+ }
+ getB() {
+ return this.b;
+ }
+ getAOrB() {
+ return this.getB();
+ }
+ }
+ self.JSExtendJSClass = JSExtendJSClass;
+ class JSExtendAnonymousClass {
+ constructor(a, b) {
+ this.a = a;
+ this.b = b;
+ }
+ getA() {
+ return this.a;
+ }
+ getB() {
+ return this.b;
+ }
+ getAOrB() {
+ return this.getB();
+ }
+ }
+ self.JSExtendAnonymousClass = JSExtendAnonymousClass;
+ self.anonExtendAnon = new JSExtendAnonymousClass(1, 2);
+ self.anonExtendJS = new JSExtendJSClass(1, 2);
+ """);
+}
+
void testInheritance() {
// Note that for the following, there are no meaningful tests for is checks or
// as casts, since the web compilers should return true and succeed for all JS
@@ -92,3 +194,17 @@
expect(anonExtendJS.getAOrB(), 2);
expect((anonExtendJS as JSClass).getAOrB(), 2);
}
+
+void testSubtyping() {
+ // Test subtyping for inheritance between JS and anonymous classes.
+ expect(useJSClass is void Function(JSExtendJSClass js), true);
+ expect(useAnonymousClass is void Function(AnonymousExtendAnonymousClass a),
+ true);
+ expect(useJSClass is void Function(AnonymousExtendJSClass a), true);
+ expect(useAnonymousClass is void Function(JSExtendAnonymousClass js), true);
+
+ expect(useJSClass is void Function(AnonymousExtendAnonymousClass a), false);
+ expect(useAnonymousClass is void Function(JSExtendJSClass js), false);
+ expect(useJSClass is void Function(JSExtendAnonymousClass js), false);
+ expect(useAnonymousClass is void Function(AnonymousExtendJSClass a), false);
+}
diff --git a/tests/lib/js/extends_test/extends_with_es6_subtyping_test.dart b/tests/lib/js/extends_test/extends_with_es6_subtyping_test.dart
new file mode 100644
index 0000000..e6185da
--- /dev/null
+++ b/tests/lib/js/extends_test/extends_with_es6_subtyping_test.dart
@@ -0,0 +1,10 @@
+// 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 'extends_test_util.dart';
+
+void main() {
+ setUpWithES6Syntax();
+ testSubtyping();
+}
diff --git a/tests/lib/js/extends_test/extends_with_es6_test.dart b/tests/lib/js/extends_test/extends_with_es6_test.dart
index 00eb41f..8daae16 100644
--- a/tests/lib/js/extends_test/extends_with_es6_test.dart
+++ b/tests/lib/js/extends_test/extends_with_es6_test.dart
@@ -5,50 +5,6 @@
import 'extends_test_util.dart';
void main() {
- // Use the ES6 syntax for classes to make inheritance easier.
- eval(r"""
- class JSClass {
- constructor(a) {
- this.a = a;
- }
- getA() {
- return this.a;
- }
- getAOrB() {
- return this.getA();
- }
- }
- class JSExtendJSClass extends JSClass {
- constructor(a, b) {
- super(a);
- this.b = b;
- }
- getB() {
- return this.b;
- }
- getAOrB() {
- return this.getB();
- }
- }
- self.JSExtendJSClass = JSExtendJSClass;
- class JSExtendAnonymousClass {
- constructor(a, b) {
- this.a = a;
- this.b = b;
- }
- getA() {
- return this.a;
- }
- getB() {
- return this.b;
- }
- getAOrB() {
- return this.getB();
- }
- }
- self.JSExtendAnonymousClass = JSExtendAnonymousClass;
- self.anonExtendAnon = new JSExtendAnonymousClass(1, 2);
- self.anonExtendJS = new JSExtendJSClass(1, 2);
- """);
+ setUpWithES6Syntax();
testInheritance();
}
diff --git a/tests/lib/js/is_check_and_as_cast_test.dart b/tests/lib/js/is_check_and_as_cast_test.dart
index ef48137..d88255c 100644
--- a/tests/lib/js/is_check_and_as_cast_test.dart
+++ b/tests/lib/js/is_check_and_as_cast_test.dart
@@ -9,6 +9,7 @@
library is_check_and_as_cast_test;
import 'package:js/js.dart';
+import 'package:expect/expect.dart' show hasUnsoundNullSafety;
import 'package:expect/minitest.dart';
@JS()
@@ -57,6 +58,8 @@
external LiteralA get a;
external LiteralB get b;
+class DartClass {}
+
void main() {
eval(r"""
function Foo(a) {
@@ -119,4 +122,26 @@
expect(() => (foo as LiteralB), returnsNormally);
expect(a is Foo, isTrue);
expect(() => (a as Foo), returnsNormally);
+
+ // You cannot cast between JS interop objects and Dart objects, however.
+ var dartClass = DartClass();
+ expect(dartClass is Foo, isFalse);
+ expect(() => (dartClass as Foo), throws);
+ expect(dartClass is LiteralA, isFalse);
+ expect(() => (dartClass as LiteralA), throws);
+
+ expect(foo is DartClass, isFalse);
+ expect(() => (foo as DartClass), throws);
+ expect(a is DartClass, isFalse);
+ expect(() => (a as DartClass), throws);
+
+ // Test that nullability is still respected with JS types.
+ Foo? nullableFoo = null;
+ expect(nullableFoo is Foo, false);
+ expect(() => (nullableFoo as Foo),
+ hasUnsoundNullSafety ? returnsNormally : throws);
+ LiteralA? nullableA = null;
+ expect(nullableA is LiteralA, false);
+ expect(() => (nullableA as LiteralA),
+ hasUnsoundNullSafety ? returnsNormally : throws);
}
diff --git a/tests/lib/js/subtyping_test.dart b/tests/lib/js/subtyping_test.dart
new file mode 100644
index 0000000..2551fcd
--- /dev/null
+++ b/tests/lib/js/subtyping_test.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.
+
+// Tests subtyping relationships between JS and anonymous classes.
+
+@JS()
+library subtyping_test;
+
+import 'package:js/js.dart';
+import 'package:expect/expect.dart' show hasUnsoundNullSafety;
+import 'package:expect/minitest.dart';
+
+@JS()
+class JSClassA {}
+
+@JS()
+class JSClassB {}
+
+@JS()
+@anonymous
+class AnonymousClassA {}
+
+@JS()
+@anonymous
+class AnonymousClassB {}
+
+class DartClass {}
+
+void useJSClassA(JSClassA _) {}
+void useAnonymousClassA(AnonymousClassA _) {}
+void useDartClass(DartClass _) {}
+
+void useNullableJSClassA(JSClassA? _) {}
+void useNullableAnonymousClassA(AnonymousClassA? _) {}
+
+// Avoid static type optimization by running all tests using this.
+@pragma('dart2js:noInline')
+@pragma('dart2js:assumeDynamic')
+confuse(x) => x;
+
+void main() {
+ // Checks subtyping with the same type and nullability subtyping.
+ expect(useJSClassA is void Function(JSClassA), true);
+ expect(useAnonymousClassA is void Function(AnonymousClassA), true);
+ expect(useJSClassA is void Function(JSClassA?), hasUnsoundNullSafety);
+ expect(useAnonymousClassA is void Function(AnonymousClassA?),
+ hasUnsoundNullSafety);
+ expect(useNullableJSClassA is void Function(JSClassA?), true);
+ expect(useNullableAnonymousClassA is void Function(AnonymousClassA?), true);
+ expect(useNullableJSClassA is void Function(JSClassA), true);
+ expect(useNullableAnonymousClassA is void Function(AnonymousClassA), true);
+
+ expect(confuse(useJSClassA) is void Function(JSClassA), true);
+ expect(confuse(useAnonymousClassA) is void Function(AnonymousClassA), true);
+ expect(
+ confuse(useJSClassA) is void Function(JSClassA?), hasUnsoundNullSafety);
+ expect(confuse(useAnonymousClassA) is void Function(AnonymousClassA?),
+ hasUnsoundNullSafety);
+ expect(confuse(useNullableJSClassA) is void Function(JSClassA?), true);
+ expect(confuse(useNullableAnonymousClassA) is void Function(AnonymousClassA?),
+ true);
+ expect(confuse(useNullableJSClassA) is void Function(JSClassA), true);
+ expect(confuse(useNullableAnonymousClassA) is void Function(AnonymousClassA),
+ true);
+
+ // No subtyping between JS and anonymous classes.
+ expect(useJSClassA is void Function(AnonymousClassA), false);
+ expect(useAnonymousClassA is void Function(JSClassA), false);
+
+ expect(confuse(useJSClassA) is void Function(AnonymousClassA), false);
+ expect(confuse(useAnonymousClassA) is void Function(JSClassA), false);
+
+ // No subtyping between separate classes even if they're both JS classes or
+ // anonymous classes.
+ expect(useJSClassA is void Function(JSClassB), false);
+ expect(useAnonymousClassA is void Function(AnonymousClassB), false);
+
+ expect(confuse(useJSClassA) is void Function(JSClassB), false);
+ expect(confuse(useAnonymousClassA) is void Function(AnonymousClassB), false);
+
+ // No subtyping between JS/anonymous classes and Dart classes.
+ expect(useJSClassA is void Function(DartClass), false);
+ expect(useAnonymousClassA is void Function(DartClass), false);
+
+ expect(confuse(useJSClassA) is void Function(DartClass), false);
+ expect(confuse(useAnonymousClassA) is void Function(DartClass), false);
+}
diff --git a/tests/lib_2/async/future_error_test.dart b/tests/lib_2/async/future_error_test.dart
index 3ef0eb3..bb96fa3 100644
--- a/tests/lib_2/async/future_error_test.dart
+++ b/tests/lib_2/async/future_error_test.dart
@@ -7,7 +7,7 @@
main() {
// The error cannot be null.
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
Future.error(null);
});
}
diff --git a/tests/lib_2/async/future_test.dart b/tests/lib_2/async/future_test.dart
index 6c227cf..2e546bf 100644
--- a/tests/lib_2/async/future_test.dart
+++ b/tests/lib_2/async/future_test.dart
@@ -709,7 +709,7 @@
void testCompleteErrorWithNull() {
final completer = new Completer<int>();
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
completer.completeError(null);
});
}
diff --git a/tests/lib_2/async/stream_controller_add_error_test.dart b/tests/lib_2/async/stream_controller_add_error_test.dart
index aed39e8..fe24ceb 100644
--- a/tests/lib_2/async/stream_controller_add_error_test.dart
+++ b/tests/lib_2/async/stream_controller_add_error_test.dart
@@ -8,41 +8,41 @@
main() {
// Single-cast async.
var controller = StreamController();
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.addError(null);
});
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null);
});
// Single-cast sync.
controller = StreamController(sync: true);
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.addError(null);
});
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null);
});
// Broadcast async.
controller = StreamController.broadcast();
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.addError(null);
});
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null);
});
// Broadcast sync.
controller = StreamController.broadcast(sync: true);
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.addError(null);
});
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
controller.sink.addError(null);
});
}
diff --git a/tests/lib_2/async/stream_error_test.dart b/tests/lib_2/async/stream_error_test.dart
index 22b091b..1c0737e 100644
--- a/tests/lib_2/async/stream_error_test.dart
+++ b/tests/lib_2/async/stream_error_test.dart
@@ -73,7 +73,7 @@
}
// A null error argument is a synchronous error.
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
Stream.error(null);
});
diff --git a/tests/lib_2/async/zone_async_error_test.dart b/tests/lib_2/async/zone_async_error_test.dart
index b1f67ce..ad3709d 100644
--- a/tests/lib_2/async/zone_async_error_test.dart
+++ b/tests/lib_2/async/zone_async_error_test.dart
@@ -7,7 +7,7 @@
main() {
// The error cannot be null.
- Expect.throwsArgumentError(() {
+ Expect.throwsTypeError(() {
AsyncError(null, StackTrace.current);
});
}
diff --git a/tools/VERSION b/tools/VERSION
index d10bed3..31011dd 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 31
+PRERELEASE 32
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/lib/src/firestore.dart b/tools/bots/lib/src/firestore.dart
index 44344e2..166173c 100644
--- a/tools/bots/lib/src/firestore.dart
+++ b/tools/bots/lib/src/firestore.dart
@@ -70,7 +70,7 @@
var response = await _client.get(url, headers: _headers);
if (response.statusCode == HttpStatus.ok) {
var document = jsonDecode(response.body);
- if (!document is Map) {
+ if (document is! Map) {
throw _error(response, message: 'Expected a Map');
}
return document;
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index dfe661f..8d4be38 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -45,7 +45,6 @@
"tests/corelib_2/",
"tests/dart2js_2/",
"tests/dartdevc_2/",
- "tests/kernel/",
"tests/language/",
"tests/language_2/",
"tests/lib_2/",
@@ -86,7 +85,6 @@
"tests/corelib/",
"tests/dart2js/",
"tests/dartdevc/",
- "tests/kernel/",
"tests/language/",
"tests/language_2/",
"tests/lib/",
@@ -134,7 +132,6 @@
"tests/corelib_2/",
"tests/dart2js_2/",
"tests/dartdevc_2/",
- "tests/kernel/",
"tests/language/",
"tests/language_2/",
"tests/lib_2/",
@@ -178,7 +175,6 @@
"tests/corelib/",
"tests/dart2js/",
"tests/dartdevc/",
- "tests/kernel/",
"tests/language/",
"tests/language_2/",
"tests/lib/",
@@ -225,7 +221,6 @@
"tests/dart2js_2/",
"tests/dartdevc/",
"tests/dartdevc_2/",
- "tests/kernel/",
"tests/language/",
"tests/language_2/",
"tests/lib/",
@@ -336,7 +331,6 @@
"tests/dart2js_2/",
"tests/dartdevc",
"tests/dartdevc_2",
- "tests/kernel/",
"tests/language/",
"tests/language_2/",
"tests/lib/",
diff --git a/tools/generate_idefiles.py b/tools/generate_idefiles.py
index ebaae9c..5727e49 100755
--- a/tools/generate_idefiles.py
+++ b/tools/generate_idefiles.py
@@ -111,7 +111,6 @@
- tests/dartdevc_2/**
- tests/ffi/**
- tests/ffi_2/**
- - tests/kernel/**
- tests/language/**
- tests/language_2/**
- tests/lib/**